sl@0: /* sl@0: * Copyright (c) 2006-2009 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: sl@0: /** sl@0: @file sl@0: @test sl@0: @internalComponent Internal Symbian test code sl@0: */ sl@0: sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include "ShaperCache.H" sl@0: #include "openfontsprivate.h" sl@0: sl@0: #include "T_SHAPERCACHE.H" sl@0: #include "T_FSOPEN.H" sl@0: sl@0: _LIT(KFontDummy,"z:\\PlatTest\\Graphics\\TestData\\dummy_fonts\\dummy"); sl@0: _LIT(KFontDummy_b,"z:\\PlatTest\\Graphics\\TestData\\dummy_fonts\\dummy_b"); sl@0: _LIT(KFontDummy_i,"z:\\PlatTest\\Graphics\\TestData\\dummy_fonts\\dummy_i"); sl@0: _LIT(KFontDummy_bi,"z:\\PlatTest\\Graphics\\TestData\\dummy_fonts\\dummy_bi"); sl@0: sl@0: const TUint32 KDevanagariScriptCode = 0x64657661; sl@0: _LIT16(KTextToShape, "\x0915\x094D\x0937\x0924\x094D\x0930\x093F\x092F"); sl@0: const TInt KResultNumberOfGlyphs = 4; sl@0: sl@0: CTShaperCache::~CTShaperCache() sl@0: { sl@0: delete iFontStore; sl@0: iHeap->__DbgMarkEnd(0); sl@0: iHeap->Close(); sl@0: __UHEAP_MARKEND; sl@0: User::Heap().Check(); sl@0: } sl@0: sl@0: CTShaperCache::CTShaperCache(CTestStep* aStep): sl@0: CTGraphicsBase(aStep) sl@0: { sl@0: INFO_PRINTF1(_L("FontStore T_ShaperCache test\n")); sl@0: } sl@0: sl@0: void CTShaperCache::ConstructL() sl@0: { sl@0: __UHEAP_MARK; sl@0: iHeap = UserHeap::ChunkHeap(NULL,0x10000,0x100000); sl@0: if (iHeap == NULL) sl@0: User::Leave(KErrGeneral); sl@0: iHeap->__DbgMarkStart(); sl@0: iFontStore = CFontStore::NewL(iHeap); sl@0: sl@0: // Install the dummy rasterizer. sl@0: COpenFontRasterizer* r = CDummyRasterizer::NewL(); sl@0: CleanupStack::PushL(r); sl@0: iFontStore->InstallRasterizerL(r); sl@0: CleanupStack::Pop(); sl@0: sl@0: // Install the dummy shaper sl@0: CShaperFactory* shaperFactory = CDummyShaperFactory::NewL(); sl@0: CleanupStack::PushL(shaperFactory); sl@0: iFontStore->InstallShaperFactoryL(shaperFactory); sl@0: CleanupStack::Pop(); sl@0: } sl@0: sl@0: /** sl@0: @SYMTestCaseID sl@0: GRAPHICS-FNTSTORE-0043 sl@0: sl@0: @SYMTestCaseDesc sl@0: Tests creating and deleting a new shaper cache entry. sl@0: sl@0: @SYMTestActions sl@0: 1. Allocated a TShapeHeader object on the heap/ sl@0: 2. Creates a CShaper object on the stack. sl@0: 3. Allocates an entry for the TShapeHeader object in the cache. sl@0: 4. Frees memory taken up by the entry to the cache. sl@0: 5. The heap is checked for memory leaks. sl@0: sl@0: @SYMTestExpectedResults sl@0: No memory leaks should exist. sl@0: */ sl@0: void CTShaperCache::Test1L() sl@0: { sl@0: INFO_PRINTF1(_L("ShaperCache Test1")); sl@0: __UHEAP_MARK; sl@0: sl@0: TShapeHeader* shapeHeader=new TShapeHeader(); sl@0: shapeHeader->iGlyphCount=10; sl@0: shapeHeader->iCharacterCount=20; sl@0: sl@0: _LIT(KDummyText,"dummy"); sl@0: CShaper::TInput input; sl@0: input.iStart=0; sl@0: input.iEnd=10; sl@0: input.iText=&(KDummyText()); sl@0: sl@0: //create/delete test a new shaper cache entry sl@0: COpenFontShaperCacheEntry* shapeEntry=COpenFontShaperCacheEntry::New(&User::Heap(),input,shapeHeader); sl@0: COpenFontShaperCacheEntry::Delete(&User::Heap(),shapeEntry); sl@0: sl@0: delete shapeHeader; sl@0: sl@0: __UHEAP_MARKEND; sl@0: } sl@0: sl@0: /** sl@0: @SYMTestCaseID sl@0: GRAPHICS-FNTSTORE-0044 sl@0: sl@0: @SYMTestCaseDesc sl@0: Tests ncrementation and decrementation of the reference sl@0: count for a particular session handle. sl@0: sl@0: @SYMTestActions sl@0: 1. Creates a TShapeHeader object on the heap. sl@0: 2. Set som values to the object. sl@0: 3. Creates a CShaper object on the stack. sl@0: 4. Creates a new shaper cache entry. sl@0: 5. Associates a session with this entry. sl@0: 6. Increments the reference count for a particular session (A) handle. sl@0: 7. Increments the reference count for another session (B). sl@0: 8. Decrements an instance from session (A). sl@0: 9. Adds another session to the list (C). sl@0: 10. Decrements the ref count for a particular session handle (C). sl@0: 11. Tests decrement on non-existent session. sl@0: 12. Frees memory taken up by the entry to the cache. sl@0: 13. The heap is checked for memory leaks. sl@0: sl@0: @SYMTestExpectedResults sl@0: The decrementation of the non-existent session should return KErrNotFound. sl@0: */ sl@0: void CTShaperCache::Test2L() sl@0: { sl@0: INFO_PRINTF1(_L("ShaperCache Test2")); sl@0: __UHEAP_MARK; sl@0: sl@0: TShapeHeader* shapeHeader=new TShapeHeader(); sl@0: shapeHeader->iGlyphCount=10; sl@0: shapeHeader->iCharacterCount=20; sl@0: sl@0: _LIT(KDummyText,"dummy"); sl@0: CShaper::TInput input; sl@0: input.iStart=0; sl@0: input.iEnd=10; sl@0: input.iText=&(KDummyText()); sl@0: sl@0: //create a new shaper cache entry sl@0: COpenFontShaperCacheEntry* shapeEntry=COpenFontShaperCacheEntry::New(&User::Heap(),input,shapeHeader); sl@0: sl@0: //now associate a session with this entry sl@0: TInt dummySession=12; sl@0: TEST(shapeEntry->IncRefCount(dummySession)==KErrNone); sl@0: TEST(shapeEntry->iHandleRefCount==1); sl@0: TEST(shapeEntry->iHandleRefList!=NULL); sl@0: TEST(shapeEntry->iHandleRefList->iSessionHandle==dummySession); sl@0: TEST(shapeEntry->iHandleRefList->iRefCount==1); sl@0: //increment for another session, the THandleCount::iRef for this session should be 2 sl@0: TEST(shapeEntry->IncRefCount(dummySession)==KErrNone); sl@0: TEST(shapeEntry->iHandleRefCount==1); sl@0: TEST(shapeEntry->iHandleRefList->iRefCount==2); sl@0: sl@0: //another entry for different session sl@0: TInt dummySession2=13; sl@0: TEST(shapeEntry->IncRefCount(dummySession2)==KErrNone); sl@0: TEST(shapeEntry->iHandleRefCount==2); sl@0: TEST(shapeEntry->iHandleRefList->iSessionHandle==dummySession); sl@0: TEST(shapeEntry->iHandleRefList->iRefCount==2); sl@0: TEST(shapeEntry->iHandleRefList->iNext->iSessionHandle==dummySession2); sl@0: TEST(shapeEntry->iHandleRefList->iNext->iRefCount==1); sl@0: sl@0: //now decrement an instance from this session(DELETE FIRST ENTRY) sl@0: TEST(shapeEntry->DecRefCount(dummySession)==KErrNone); sl@0: TEST(shapeEntry->iHandleRefCount==2); sl@0: TEST(shapeEntry->iHandleRefList->iNext->iRefCount==1); sl@0: TEST(shapeEntry->DecRefCount(dummySession)==KErrNone); sl@0: TEST(shapeEntry->iHandleRefCount==1); sl@0: TEST(shapeEntry->iHandleRefList->iRefCount==1); sl@0: TEST(shapeEntry->iHandleRefList->iSessionHandle=dummySession2); sl@0: sl@0: //now add another session to this list sl@0: TInt dummySession3=14; sl@0: TEST(shapeEntry->IncRefCount(dummySession3)==KErrNone); sl@0: TEST(shapeEntry->iHandleRefCount==2); sl@0: //test delete this last entry in the list(DELETE LAST ENTRY) sl@0: TEST(shapeEntry->DecRefCount(dummySession3)==KErrNone); sl@0: TEST(shapeEntry->iHandleRefCount==1); sl@0: TEST(shapeEntry->iHandleRefList->iRefCount==1); sl@0: TEST(shapeEntry->iHandleRefList->iSessionHandle==dummySession2); sl@0: sl@0: sl@0: //test Dec on non-existent session sl@0: TEST(shapeEntry->DecRefCount(100)==KErrNotFound); sl@0: sl@0: COpenFontShaperCacheEntry::Delete(&User::Heap(),shapeEntry); sl@0: delete shapeHeader; sl@0: sl@0: __UHEAP_MARKEND; sl@0: } sl@0: sl@0: /** sl@0: @SYMTestCaseID sl@0: GRAPHICS-FNTSTORE-0045 sl@0: sl@0: @SYMTestCaseDesc sl@0: Tests the shaper cache APIs. sl@0: sl@0: @SYMTestActions sl@0: 1. Creates a dummy TShapeHeader object that will be cached and reused through the test. sl@0: 2. Gets some memory to pass back the results. It needs to be big enough for a TShapeHeader sl@0: object plus 10 bytes for every glyph returned. sl@0: 3. Finds or creates four font file objects to support a font file. sl@0: 4. Gets the number of supported typefaces. sl@0: 5. Creates a font. sl@0: 6. Gets a COpenFont object. sl@0: 7. For COpenFonts it attempts to put this into the shaper cache and test if it was successful. sl@0: 8. Calls DeleteShape to decrement the reference count. sl@0: 9. Changes the shaped data slightly to make it into a new shaped data and insert into the sl@0: cache as a new entry. sl@0: 10. Tests if the LRU cache is working by seeing if the first entry in the cache is the newest one. sl@0: 11. Calls DeleteShape to decrement the reference count sl@0: 12. Calls the GetShapedData API and tests the returned TShapeHeader. Also checks if the returned sl@0: cache entry is at the top of the cache. sl@0: 13. Searches the cache for the first entry using the GetShapedData API. sl@0: 14. Calls DeleteShape to decrement the reference count. sl@0: 15. Brings the end value back to its original value. sl@0: 16. Fills the cache and then tests replacement policy by attempting to add a new entry. sl@0: 17. Prepares a raw input data structure. sl@0: 18. Keeps inserting pseudo-new shaped entries into the cache to fill it up. sl@0: 19. Changes the cached entries slightly to distinguish between each entry. sl@0: 20. Tries to add a new entry and checks that the entry replaced was the last entry in the cache. sl@0: 21. Calculates the memory needed for the new entry. sl@0: 22. Calculates the memory that will be freed to accommodate the new entry and the sl@0: position of the last entry in the cache once deletion is done. sl@0: 23. Finds the glyphcount of the expected new last entry in the cache. sl@0: 24. Does the insertion and tests. sl@0: 25. Calls DeleteShape to decrement the reference count. sl@0: 26. Calculates the memory occupied by the last entry in the cache. This is the memory that will sl@0: be released when the last entry is deleted. sl@0: 27. Tests with multiple open fonts with caches. Creates the new font. sl@0: 28. Does the testing only if the font is a COpenFont. sl@0: 29. Attempts to put a new entry into the second shaper cache and test if it was successful. sl@0: 30. Creates a pseudo-new shape header to put into the cache of this new open font. sl@0: 31. Inserst an entry into the cache. sl@0: 32. Tests cache memory freeing policy, i.e. delete from all other caches except the current one. sl@0: 33. Finds out how much memory needs freeing, i.e. how much was just added. sl@0: 34. Tries to free memory from the original open font cache. The result should be that sl@0: memory should be freed from openFont2 cache, and not openFont cache. sl@0: 35. Checks sl@0: a) if the memory used by openFont2 cache has reduced, i.e. back to original memory. sl@0: b) if the last entry from openFont2 cache has been deleted. sl@0: c) last entry from openFont cache is intact. sl@0: 36. Cleans up font2, font1 and removes all fonts. sl@0: sl@0: @SYMTestExpectedResults sl@0: All tests shall pass. sl@0: sl@0: */ sl@0: void CTShaperCache::TestShaperCacheAPIsL() sl@0: { sl@0: INFO_PRINTF1(_L("The following results are for shaper cache API tests\n")); sl@0: sl@0: // Create a dummy TShapeHeader object that will be cached, and reused all through this test sl@0: TShapeHeader* shape = 0; sl@0: sl@0: // get some memory to pass back the results, sl@0: // This needs to be big enough for a TShapeHeader sl@0: // plus 10 bytes for every glyph returned (-1 for the 1 byte allocated in TShapeHeader for iBuffer) sl@0: shape = reinterpret_cast( iHeap->AllocL(sizeof(TShapeHeader) + (KResultNumberOfGlyphs * 10) + 3) ); sl@0: sl@0: // get the results into the shaper structure 'shape' sl@0: shape->iGlyphCount = KResultNumberOfGlyphs; sl@0: shape->iCharacterCount = 8; sl@0: shape->iReserved0 = 0; sl@0: shape->iReserved1 = 0; sl@0: sl@0: // iBuffer contains 10 bytes for every glyph sl@0: // the glyph code (4 bytes), position X(2 bytes) Y(2 bytes) and indices(2 bytes) sl@0: // first is glyph count * 4 byte glyph codes sl@0: TUint32* glyphOut = reinterpret_cast(shape->iBuffer); sl@0: TInt16* posOut = reinterpret_cast(shape->iBuffer + sl@0: (4 * KResultNumberOfGlyphs)); sl@0: TInt16* indicesOut = reinterpret_cast(shape->iBuffer + sl@0: (8 * KResultNumberOfGlyphs) + 4); sl@0: sl@0: *glyphOut++ = (TUint32)1461; sl@0: *posOut++ = (TInt16)0; sl@0: *posOut++ = (TInt16)0; sl@0: *indicesOut++ = (TInt16)0; sl@0: sl@0: *glyphOut++ = (TUint32)1778; sl@0: *posOut++ = (TInt16)12; sl@0: *posOut++ = (TInt16)0; sl@0: *indicesOut++ = (TInt16)7; sl@0: sl@0: *glyphOut++ = (TUint32)1550; sl@0: *posOut++ = (TInt16)16; sl@0: *posOut++ = (TInt16)0; sl@0: *indicesOut++ = (TInt16)3; sl@0: sl@0: *glyphOut++ = (TUint32)1362; sl@0: *posOut++ = (TInt16)28; sl@0: *posOut++ = (TInt16)0; sl@0: *indicesOut++ = (TInt16)7; sl@0: sl@0: // There is an extra pair of positions: this is the total advance sl@0: posOut[0] = (TInt16)28; sl@0: posOut[1] = (TInt16)0; sl@0: sl@0: TFontShapeFunctionParameters* params; sl@0: params = reinterpret_cast( iHeap->AllocL(sizeof(TFontShapeFunctionParameters))); sl@0: params->iEnd = 8; sl@0: params->iLanguage = 0; sl@0: params->iScript = KDevanagariScriptCode; sl@0: params->iStart = 0; sl@0: //TBufC16<9> text(KTextToShape); sl@0: params->iText = &KTextToShape(); sl@0: sl@0: // Add fonts sl@0: TUid id1 = iFontStore->AddFileL(KFontDummy); sl@0: TUid id2 = iFontStore->AddFileL(KFontDummy_b); sl@0: TUid id3 = iFontStore->AddFileL(KFontDummy_i); sl@0: TUid id4 = iFontStore->AddFileL(KFontDummy_bi); sl@0: sl@0: INFO_PRINTF1(_L("SHAPER CACHE API TESTS SET 1: Testing cache with a single COpentFont cache")); sl@0: sl@0: TInt typefaces = iFontStore->NumTypefaces(); sl@0: TInt typeface = 0; sl@0: TInt height = 12; sl@0: sl@0: TTypefaceSupport support; sl@0: iFontStore->TypefaceSupport(support,typeface); sl@0: TFontSpec fs; sl@0: fs.iTypeface = support.iTypeface; sl@0: sl@0: INFO_PRINTF3(_L("Typeface is %d and height is %d"), typeface, height); sl@0: //Create a font sl@0: CFont* font = NULL; sl@0: fs.iHeight = iFontStore->FontHeightInTwips(typeface,height); sl@0: // get a COpenFont object sl@0: iFontStore->GetNearestFontToDesignHeightInPixels(font, fs); sl@0: CleanupStack::PushL(font); sl@0: sl@0: sl@0: // Do the testing only if the font is a COpenFont sl@0: COpenFont* openFont = NULL; sl@0: CShaper::TInput input; sl@0: if (((CBitmapFont*)font)->IsOpenFont()) sl@0: { sl@0: __UHEAP_MARK; sl@0: openFont = ((CBitmapFont*)font)->OpenFont(); sl@0: sl@0: /***************************First Test*************************** sl@0: Attempt to put this into the shaper cache and then delete it. Test if it was successful sl@0: */ sl@0: TShapeHeader* cached_header = openFont->InsertShapedDataIntoCache(0,params, shape); sl@0: sl@0: INFO_PRINTF1(_L("SHAPER CACHE API TEST 1: Simple cache insertion test")); sl@0: TEST(cached_header != NULL && openFont->GetGlyphCache()->iNumberOfShaperCacheEntries == 2); sl@0: sl@0: /* Call DeleteShape to decrement the reference count */ sl@0: ((CBitmapFont*)font)->DeleteShape(0, cached_header); sl@0: sl@0: // Now delete this data sl@0: openFont->FreeShaperCacheMemory(openFont->GetGlyphCache()->iShapingInfoCacheMemory); sl@0: TEST(openFont->GetGlyphCache()->iNumberOfShaperCacheEntries == 1); sl@0: // Put the shaped data back into the cache to continue with testing sl@0: cached_header = openFont->InsertShapedDataIntoCache(0,params, shape); sl@0: TEST(cached_header != NULL && openFont->GetGlyphCache()->iNumberOfShaperCacheEntries == 2); sl@0: ((CBitmapFont*)font)->DeleteShape(0, cached_header); sl@0: sl@0: /**************************Second Test************************** sl@0: Now change the shaped data slightly to make it into a new shaped data and insert into the sl@0: cache as a new entry sl@0: */ sl@0: shape->iGlyphCount++; sl@0: params->iEnd++; sl@0: TShapeHeader* cached_header2 = openFont->InsertShapedDataIntoCache(0,params, shape); sl@0: sl@0: /* Now test if the LRU cache is working by seeing if the first entry in the cache is the newest one */ sl@0: COpenFontGlyphCache* glyphCache = openFont->GetGlyphCache(); sl@0: sl@0: INFO_PRINTF1(_L("SHAPER CACHE API TEST 2: Test the LRU (Least Recently Used) cache structure")); sl@0: TEST(glyphCache->iShaperCacheSentinel->iNext->iShapeHeader->iGlyphCount == KResultNumberOfGlyphs + 1); sl@0: sl@0: /* Call DeleteShape to decrement the reference count */ sl@0: ((CBitmapFont*)font)->DeleteShape(0, cached_header2); sl@0: sl@0: sl@0: /**************************Third Test************************** sl@0: Call the GetShapedData API and test the returned TShapeHeader, and also check if the returned sl@0: cache entry is now at the top of the cache sl@0: */ sl@0: sl@0: /* Now search the cache for the first entry using the GetShapedData API */ sl@0: params->iEnd --; sl@0: TInt expectedGlyphCount = glyphCache->iShaperCacheSentinel->iPrevious->iShapeHeader->iGlyphCount; sl@0: TShapeHeader* searchedCachedHeader = openFont->GetShapedData(0,params); sl@0: sl@0: INFO_PRINTF1(_L("SHAPER CACHE API TEST 3: GetShapedData API test")); sl@0: TEST(searchedCachedHeader->iGlyphCount == expectedGlyphCount && sl@0: searchedCachedHeader->iGlyphCount ==glyphCache->iShaperCacheSentinel->iNext->iShapeHeader->iGlyphCount); sl@0: sl@0: /* Call DeleteShape to decrement the reference count */ sl@0: ((CBitmapFont*)font)->DeleteShape(0, searchedCachedHeader); sl@0: sl@0: /* Bring the end value back to its original value */ sl@0: params->iEnd ++; sl@0: sl@0: sl@0: /**************************Fourth Test************************** sl@0: Fill the cache and then test replacement policy by attempting to add a new entry sl@0: */ sl@0: sl@0: /* First prepare a raw input data structure */ sl@0: TInt memoryUsed = 0; sl@0: input.iText = &KTextToShape(); sl@0: input.iStart = 0; sl@0: input.iEnd = params->iEnd; sl@0: input.iScript= KDevanagariScriptCode; sl@0: input.iLanguage = 0; sl@0: input.iMaximumAdvance = KMaxTInt; sl@0: input.iFlags = 0; sl@0: input.iSessionHandle = 0; sl@0: input.iReserved1 = 0; sl@0: TInt addedBytes = 0; sl@0: TShapeHeader* chached_header3 = 0; sl@0: openFont->FreeShaperCacheMemory(KMaxShaperSesssionCacheMemory); sl@0: openFont->File()->GetFontStore()->SetShaperCacheMemUsage(0); sl@0: RArray cacheMemUsage; sl@0: /* Keep inserting pseudo-new shaped entries into the cache to fill it up */ sl@0: while(openFont->File()->GetFontStore()->GetShaperCacheMemUsage() < KMaxShaperSesssionCacheMemory) sl@0: { sl@0: memoryUsed = openFont->File()->GetFontStore()->GetShaperCacheMemUsage(); sl@0: // Change the cached entries slightly to distinguish between each entry sl@0: shape->iGlyphCount++; sl@0: input.iEnd++; sl@0: chached_header3 = glyphCache->Insert(0,iHeap, input, shape, addedBytes); sl@0: if (chached_header3 != NULL) sl@0: openFont->File()->GetFontStore()->SetShaperCacheMemUsage(memoryUsed + addedBytes); sl@0: ((CBitmapFont*)font)->DeleteShape(0, chached_header3); sl@0: cacheMemUsage.AppendL(openFont->File()->GetFontStore()->GetShaperCacheMemUsage() - memoryUsed); sl@0: chached_header3 = NULL; sl@0: } sl@0: sl@0: /* Now try to add a new entry, and check that the entry replaced was the last entry in the cache */ sl@0: TInt last_entry_glyph_count = glyphCache->iShaperCacheSentinel->iPrevious->iShapeHeader->iGlyphCount; sl@0: shape->iGlyphCount++; sl@0: input.iEnd++; sl@0: params->iEnd = input.iEnd; sl@0: sl@0: /* Calculate the memory needed for the new entry */ sl@0: sl@0: sl@0: TInt heapSizeBefAloc = 0; sl@0: iHeap->AllocSize(heapSizeBefAloc); sl@0: COpenFontShaperCacheEntry *tempEntry = COpenFontShaperCacheEntry::New(iHeap, input, shape); sl@0: TInt heapSizeAftAloc = 0; sl@0: iHeap->AllocSize(heapSizeAftAloc); sl@0: TInt bytes_needed = heapSizeAftAloc - heapSizeBefAloc; sl@0: COpenFontShaperCacheEntry::Delete(iHeap, tempEntry); sl@0: sl@0: TInt bytesToDelete = 0; sl@0: sl@0: COpenFontShaperCacheEntry* previous = glyphCache->iShaperCacheSentinel->iPrevious; sl@0: /* Calculate the memory that will be freed to accommodate the new entry, sl@0: and the position of the last entry in the cache once deletion is done */ sl@0: TInt index = 0; sl@0: while (bytesToDelete <= bytes_needed) sl@0: { sl@0: sl@0: bytesToDelete += cacheMemUsage[index++]; sl@0: previous = previous->iPrevious; sl@0: } sl@0: cacheMemUsage.Close(); sl@0: /* Find the glyphcount of the expected new last entry in the cache */ sl@0: expectedGlyphCount = previous->iShapeHeader->iGlyphCount; sl@0: sl@0: /* Finally, do the insertion, and test */ sl@0: TShapeHeader* cached_header4 = openFont->InsertShapedDataIntoCache(0, params, shape); sl@0: sl@0: INFO_PRINTF1(_L("SHAPER CACHE API TEST 4: LRU cache replacement policy test")); sl@0: TEST(glyphCache->iShaperCacheSentinel->iPrevious->iShapeHeader->iGlyphCount == expectedGlyphCount); sl@0: sl@0: /* Call DeleteShape to decrement the reference cout */ sl@0: ((CBitmapFont*)font)->DeleteShape(0, cached_header4); sl@0: sl@0: sl@0: /**************************Fifth Test************************** sl@0: Simply test the FreeShaperCacheMemory API sl@0: */ sl@0: sl@0: /* Calculate the memory of occupied by the last entry in the cache. This is the memory that will sl@0: be released when the last entry is deleted sl@0: */ sl@0: last_entry_glyph_count = glyphCache->iShaperCacheSentinel->iPrevious->iShapeHeader->iGlyphCount; sl@0: TInt bufferSize = (sizeof(TUint32) + sizeof(TInt16) + sizeof(TInt16) * 2) sl@0: * last_entry_glyph_count + sizeof(TInt16) * 2; sl@0: sl@0: bytes_needed = bufferSize + sizeof(COpenFontShaperCacheEntry) + sl@0: sizeof(TShapeHeader) + sizeof(TUint16)*input.iText->Length(); sl@0: sl@0: memoryUsed = openFont->File()->GetFontStore()->GetShaperCacheMemUsage(); sl@0: expectedGlyphCount = glyphCache->iShaperCacheSentinel->iPrevious->iPrevious->iShapeHeader->iGlyphCount; sl@0: TInt memoryReleased = openFont->FreeShaperCacheMemory(bytes_needed); sl@0: sl@0: INFO_PRINTF1(_L("SHAPER CACHE API TEST 5: FreeShaperCacheMemory API test\n")); sl@0: TEST(openFont->File()->GetFontStore()->GetShaperCacheMemUsage() == memoryUsed - memoryReleased && sl@0: glyphCache->iShaperCacheSentinel->iPrevious->iShapeHeader->iGlyphCount == expectedGlyphCount); sl@0: sl@0: __UHEAP_MARKEND; sl@0: } sl@0: sl@0: INFO_PRINTF1(_L("SHAPER CACHE API TESTS SET 2: Testing cache with a two COpentFont caches")); sl@0: /* Now test with multiple open fonts with caches */ sl@0: /* Create the new font */ sl@0: height = 4; sl@0: iFontStore->TypefaceSupport(support,typeface); sl@0: fs.iTypeface = support.iTypeface; sl@0: sl@0: INFO_PRINTF3(_L("Typeface is %d and height is %d"), typeface, height); sl@0: sl@0: CFont* font2 = NULL; sl@0: fs.iHeight = iFontStore->FontHeightInTwips(typeface,height); sl@0: iFontStore->GetNearestFontToDesignHeightInPixels(font2, fs); sl@0: CleanupStack::PushL(font2); sl@0: sl@0: COpenFont* openFont2; sl@0: /* Do the testing only if the font is a COpenFont */ sl@0: if (((CBitmapFont*)font2)->IsOpenFont()) sl@0: { sl@0: __UHEAP_MARK; sl@0: openFont2 = ((CBitmapFont*)font2)->OpenFont(); sl@0: sl@0: /***************************Sixth Test*************************** sl@0: Attempt to put a new entry into the second shaper cache and test if it was successful sl@0: */ sl@0: sl@0: /* Create a pseudo-new shape header to put into the cache of this new open font */ sl@0: shape->iGlyphCount++; sl@0: params->iEnd++; sl@0: sl@0: /* Insert an entry into the cache */ sl@0: TShapeHeader* cached_header5 = openFont2->InsertShapedDataIntoCache(0, params, shape); sl@0: ((CBitmapFont*)font2)->DeleteShape(0, cached_header5); sl@0: sl@0: INFO_PRINTF1(_L("SHAPER CACHE API TEST 6: Second cache insertion test")); sl@0: TEST(cached_header5 != NULL && openFont2->GetGlyphCache()->iNumberOfShaperCacheEntries == 2); sl@0: sl@0: /***************************Seventh, Eighth and Ninth Tests*************************** sl@0: Test cache memory freeing policy, i.e. delete from all other caches except the current one sl@0: */ sl@0: sl@0: /* First find out how much memory needs freeing, i.e. how much was just added */ sl@0: TInt bufferSize = (sizeof(TUint32) + sizeof(TInt16) + sizeof(TInt16) * 2) sl@0: * shape->iGlyphCount + sizeof(TInt16) * 2; sl@0: sl@0: TInt bytes_needed = bufferSize + sizeof(COpenFontShaperCacheEntry) + sl@0: sizeof(TShapeHeader) + sizeof(TUint16)*input.iText->Length(); sl@0: sl@0: sl@0: /* Now try to free memory from the original open font cache. The result should be that sl@0: memory should be freed from openFont2 cache, and not openFont cache sl@0: */ sl@0: TInt memoryUsed = openFont2->GetGlyphCache()->iShapingInfoCacheMemory; sl@0: TInt expectedGlyphCount = openFont->GetGlyphCache()->iShaperCacheSentinel->iPrevious->iShapeHeader->iGlyphCount; sl@0: TInt deletedMemory = openFont->FreeShaperCacheMemory(bytes_needed); sl@0: sl@0: /* Now check: sl@0: a) if the memory used by openFont2 cache has reduced, i.e. back to original memory sl@0: b) if the last entry from openFont2 cache has been deleted sl@0: c) last entry from openFont cache is intact sl@0: */ sl@0: INFO_PRINTF1(_L("SHAPER CACHE API TEST 7: Test if memory is freed from second COpenFont")); sl@0: TEST(memoryUsed - openFont2->GetGlyphCache()->iShapingInfoCacheMemory == deletedMemory && sl@0: openFont2->GetGlyphCache()->iShapingInfoCacheMemory == 0); sl@0: sl@0: INFO_PRINTF1(_L("SHAPER CACHE API TEST 8: Test if last entry of second COpenFont is deleted")); sl@0: TEST(openFont2->GetGlyphCache()->iNumberOfShaperCacheEntries == 1); sl@0: sl@0: INFO_PRINTF1(_L("SHAPER CACHE API TEST 9: Test if the last entry of the first COpenFont is intact")); sl@0: TEST(openFont->GetGlyphCache()->iShaperCacheSentinel->iPrevious->iShapeHeader->iGlyphCount == expectedGlyphCount); sl@0: sl@0: /***********************************Tenth Tests***************************************** sl@0: Test cache memory consistency and that there are no leakages when deleting memory from the cache sl@0: */ sl@0: sl@0: /* Continue adding entries to second open font cache until the memory used by the first one sl@0: goes down to zero, at which point the number of cache entries should be 1, and memory from sl@0: the current open font should start getting released and eventually reach 0 when the number sl@0: of cached entries reaches 1. sl@0: */ sl@0: TShapeHeader* cached_header6 = NULL; sl@0: /* Keep inserting pseudo-new shaped entries into the cache to fill it up */ sl@0: while(openFont->GetGlyphCache()->iNumberOfShaperCacheEntries > 1) sl@0: { sl@0: memoryUsed = openFont2->File()->GetFontStore()->GetShaperCacheMemUsage(); sl@0: // Change the cached entries slightly to distinguish between each entry sl@0: shape->iGlyphCount++; sl@0: params->iEnd++; sl@0: cached_header6 = openFont2->InsertShapedDataIntoCache(0, params, shape); sl@0: ((CBitmapFont*)font2)->DeleteShape(0, cached_header6); sl@0: cached_header6 = NULL; sl@0: } sl@0: sl@0: INFO_PRINTF1(_L("SHAPER CACHE API TEST 10: Test consistency of cache memory")); sl@0: TEST(openFont->GetGlyphCache()->iShapingInfoCacheMemory == 0); sl@0: sl@0: sl@0: /** sl@0: @SYMTestCaseID GRAPHICS-SYSLIB-FNTSTORE-UT-4001 sl@0: @SYMTestCaseDesc Test that when trying to delete a shape not in the cache it sl@0: does not loop infinitely trying to find it. sl@0: @SYMTestPriority Medium sl@0: @SYMTestActions Pass a null shape header to the DeleteShape function. sl@0: @SYMTestExpectedResults The function call should return instead of looping infinitely. sl@0: @SYMDEF PDEF125354 sl@0: */ sl@0: ((CTShaperCacheStep*)iStep)->RecordTestResultL(); sl@0: ((CTShaperCacheStep*)iStep)->SetTestStepID(_L("GRAPHICS-SYSLIB-FNTSTORE-UT-4001")); sl@0: INFO_PRINTF1(_L("SHAPER CACHE API TEST 11: Test that shape not found does not loop infinitely.")); sl@0: TShapeHeader* null_header = NULL; sl@0: // Timeout set in TEF script to catch infinite loop. sl@0: ((CBitmapFont*)font2)->DeleteShape(0, null_header); sl@0: sl@0: ((CTShaperCacheStep*)iStep)->CloseTMSGraphicsStep(); sl@0: __UHEAP_MARKEND; sl@0: } sl@0: sl@0: /* Cleanup font2*/ sl@0: CleanupStack::Pop(font2); sl@0: iFontStore->ReleaseFont(font2); sl@0: sl@0: /* Cleanup font1 */ sl@0: CleanupStack::Pop(font); sl@0: iFontStore->ReleaseFont(font); sl@0: sl@0: // Remove the fonts sl@0: iFontStore->RemoveFile(id1); sl@0: iFontStore->RemoveFile(id2); sl@0: iFontStore->RemoveFile(id3); sl@0: iFontStore->RemoveFile(id4); sl@0: } sl@0: sl@0: void CTShaperCache::RunTestCaseL(TInt aCurTestCase) sl@0: { sl@0: ((CTShaperCacheStep*)iStep)->SetTestStepID(KUnknownSYMTestCaseIDName); sl@0: switch(aCurTestCase) sl@0: { sl@0: case 1: sl@0: ((CTShaperCacheStep*)iStep)->SetTestStepID(_L("GRAPHICS-FNTSTORE-0043")); sl@0: INFO_PRINTF1(_L("#################### T_SHAPERCACHE test case 1 ########################\n")); sl@0: TRAPD(err,Test1L()); sl@0: TEST(err == KErrNone); sl@0: break; sl@0: case 2: sl@0: ((CTShaperCacheStep*)iStep)->SetTestStepID(_L("GRAPHICS-FNTSTORE-0044")); sl@0: INFO_PRINTF1(_L("#################### T_SHAPERCACHE test case 2 ########################\n")); sl@0: TRAP(err,Test2L()); sl@0: TEST(err == KErrNone); sl@0: break; sl@0: case 3: sl@0: ((CTShaperCacheStep*)iStep)->SetTestStepID(_L("GRAPHICS-FNTSTORE-0045")); sl@0: INFO_PRINTF1(_L("#################### T_SHAPERCACHE test case 3 ########################")); sl@0: TRAP(err,TestShaperCacheAPIsL()); sl@0: TEST(err == KErrNone); sl@0: break; sl@0: case 4: sl@0: ((CTShaperCacheStep*)iStep)->SetTestStepID(KNotATestSYMTestCaseIDName); sl@0: ((CTShaperCacheStep*)iStep)->CloseTMSGraphicsStep(); sl@0: TestComplete(); sl@0: break; sl@0: } sl@0: ((CTShaperCacheStep*)iStep)->RecordTestResultL(); sl@0: } sl@0: sl@0: sl@0: //-------------- sl@0: __CONSTRUCT_STEP__(ShaperCache) sl@0: sl@0: sl@0: