1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/textandloc/fontservices/fontstore/tfs/T_SHAPERCACHE.CPP Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,698 @@
1.4 +/*
1.5 +* Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
1.6 +* All rights reserved.
1.7 +* This component and the accompanying materials are made available
1.8 +* under the terms of "Eclipse Public License v1.0"
1.9 +* which accompanies this distribution, and is available
1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.11 +*
1.12 +* Initial Contributors:
1.13 +* Nokia Corporation - initial contribution.
1.14 +*
1.15 +* Contributors:
1.16 +*
1.17 +* Description:
1.18 +*
1.19 +*/
1.20 +
1.21 +
1.22 +/**
1.23 + @file
1.24 + @test
1.25 + @internalComponent Internal Symbian test code
1.26 +*/
1.27 +
1.28 +
1.29 +#include <f32file.h>
1.30 +#include <e32test.h>
1.31 +#include <fntstore.h>
1.32 +#include <graphics/shapeimpl.h>
1.33 +#include "ShaperCache.H"
1.34 +#include "openfontsprivate.h"
1.35 +
1.36 +#include "T_SHAPERCACHE.H"
1.37 +#include "T_FSOPEN.H"
1.38 +
1.39 +_LIT(KFontDummy,"z:\\PlatTest\\Graphics\\TestData\\dummy_fonts\\dummy");
1.40 +_LIT(KFontDummy_b,"z:\\PlatTest\\Graphics\\TestData\\dummy_fonts\\dummy_b");
1.41 +_LIT(KFontDummy_i,"z:\\PlatTest\\Graphics\\TestData\\dummy_fonts\\dummy_i");
1.42 +_LIT(KFontDummy_bi,"z:\\PlatTest\\Graphics\\TestData\\dummy_fonts\\dummy_bi");
1.43 +
1.44 +const TUint32 KDevanagariScriptCode = 0x64657661;
1.45 +_LIT16(KTextToShape, "\x0915\x094D\x0937\x0924\x094D\x0930\x093F\x092F");
1.46 +const TInt KResultNumberOfGlyphs = 4;
1.47 +
1.48 +CTShaperCache::~CTShaperCache()
1.49 + {
1.50 + delete iFontStore;
1.51 + iHeap->__DbgMarkEnd(0);
1.52 + iHeap->Close();
1.53 + __UHEAP_MARKEND;
1.54 + User::Heap().Check();
1.55 + }
1.56 +
1.57 +CTShaperCache::CTShaperCache(CTestStep* aStep):
1.58 + CTGraphicsBase(aStep)
1.59 + {
1.60 + INFO_PRINTF1(_L("FontStore T_ShaperCache test\n"));
1.61 + }
1.62 +
1.63 +void CTShaperCache::ConstructL()
1.64 + {
1.65 + __UHEAP_MARK;
1.66 + iHeap = UserHeap::ChunkHeap(NULL,0x10000,0x100000);
1.67 + if (iHeap == NULL)
1.68 + User::Leave(KErrGeneral);
1.69 + iHeap->__DbgMarkStart();
1.70 + iFontStore = CFontStore::NewL(iHeap);
1.71 +
1.72 + // Install the dummy rasterizer.
1.73 + COpenFontRasterizer* r = CDummyRasterizer::NewL();
1.74 + CleanupStack::PushL(r);
1.75 + iFontStore->InstallRasterizerL(r);
1.76 + CleanupStack::Pop();
1.77 +
1.78 + // Install the dummy shaper
1.79 + CShaperFactory* shaperFactory = CDummyShaperFactory::NewL();
1.80 + CleanupStack::PushL(shaperFactory);
1.81 + iFontStore->InstallShaperFactoryL(shaperFactory);
1.82 + CleanupStack::Pop();
1.83 + }
1.84 +
1.85 +/**
1.86 + @SYMTestCaseID
1.87 + GRAPHICS-FNTSTORE-0043
1.88 +
1.89 + @SYMTestCaseDesc
1.90 + Tests creating and deleting a new shaper cache entry.
1.91 +
1.92 + @SYMTestActions
1.93 + 1. Allocated a TShapeHeader object on the heap/
1.94 + 2. Creates a CShaper object on the stack.
1.95 + 3. Allocates an entry for the TShapeHeader object in the cache.
1.96 + 4. Frees memory taken up by the entry to the cache.
1.97 + 5. The heap is checked for memory leaks.
1.98 +
1.99 + @SYMTestExpectedResults
1.100 + No memory leaks should exist.
1.101 +*/
1.102 +void CTShaperCache::Test1L()
1.103 + {
1.104 + INFO_PRINTF1(_L("ShaperCache Test1"));
1.105 + __UHEAP_MARK;
1.106 +
1.107 + TShapeHeader* shapeHeader=new TShapeHeader();
1.108 + shapeHeader->iGlyphCount=10;
1.109 + shapeHeader->iCharacterCount=20;
1.110 +
1.111 + _LIT(KDummyText,"dummy");
1.112 + CShaper::TInput input;
1.113 + input.iStart=0;
1.114 + input.iEnd=10;
1.115 + input.iText=&(KDummyText());
1.116 +
1.117 + //create/delete test a new shaper cache entry
1.118 + COpenFontShaperCacheEntry* shapeEntry=COpenFontShaperCacheEntry::New(&User::Heap(),input,shapeHeader);
1.119 + COpenFontShaperCacheEntry::Delete(&User::Heap(),shapeEntry);
1.120 +
1.121 + delete shapeHeader;
1.122 +
1.123 + __UHEAP_MARKEND;
1.124 + }
1.125 +
1.126 +/**
1.127 + @SYMTestCaseID
1.128 + GRAPHICS-FNTSTORE-0044
1.129 +
1.130 + @SYMTestCaseDesc
1.131 + Tests ncrementation and decrementation of the reference
1.132 + count for a particular session handle.
1.133 +
1.134 + @SYMTestActions
1.135 + 1. Creates a TShapeHeader object on the heap.
1.136 + 2. Set som values to the object.
1.137 + 3. Creates a CShaper object on the stack.
1.138 + 4. Creates a new shaper cache entry.
1.139 + 5. Associates a session with this entry.
1.140 + 6. Increments the reference count for a particular session (A) handle.
1.141 + 7. Increments the reference count for another session (B).
1.142 + 8. Decrements an instance from session (A).
1.143 + 9. Adds another session to the list (C).
1.144 + 10. Decrements the ref count for a particular session handle (C).
1.145 + 11. Tests decrement on non-existent session.
1.146 + 12. Frees memory taken up by the entry to the cache.
1.147 + 13. The heap is checked for memory leaks.
1.148 +
1.149 + @SYMTestExpectedResults
1.150 + The decrementation of the non-existent session should return KErrNotFound.
1.151 +*/
1.152 +void CTShaperCache::Test2L()
1.153 + {
1.154 + INFO_PRINTF1(_L("ShaperCache Test2"));
1.155 + __UHEAP_MARK;
1.156 +
1.157 + TShapeHeader* shapeHeader=new TShapeHeader();
1.158 + shapeHeader->iGlyphCount=10;
1.159 + shapeHeader->iCharacterCount=20;
1.160 +
1.161 + _LIT(KDummyText,"dummy");
1.162 + CShaper::TInput input;
1.163 + input.iStart=0;
1.164 + input.iEnd=10;
1.165 + input.iText=&(KDummyText());
1.166 +
1.167 + //create a new shaper cache entry
1.168 + COpenFontShaperCacheEntry* shapeEntry=COpenFontShaperCacheEntry::New(&User::Heap(),input,shapeHeader);
1.169 +
1.170 + //now associate a session with this entry
1.171 + TInt dummySession=12;
1.172 + TEST(shapeEntry->IncRefCount(dummySession)==KErrNone);
1.173 + TEST(shapeEntry->iHandleRefCount==1);
1.174 + TEST(shapeEntry->iHandleRefList!=NULL);
1.175 + TEST(shapeEntry->iHandleRefList->iSessionHandle==dummySession);
1.176 + TEST(shapeEntry->iHandleRefList->iRefCount==1);
1.177 + //increment for another session, the THandleCount::iRef for this session should be 2
1.178 + TEST(shapeEntry->IncRefCount(dummySession)==KErrNone);
1.179 + TEST(shapeEntry->iHandleRefCount==1);
1.180 + TEST(shapeEntry->iHandleRefList->iRefCount==2);
1.181 +
1.182 + //another entry for different session
1.183 + TInt dummySession2=13;
1.184 + TEST(shapeEntry->IncRefCount(dummySession2)==KErrNone);
1.185 + TEST(shapeEntry->iHandleRefCount==2);
1.186 + TEST(shapeEntry->iHandleRefList->iSessionHandle==dummySession);
1.187 + TEST(shapeEntry->iHandleRefList->iRefCount==2);
1.188 + TEST(shapeEntry->iHandleRefList->iNext->iSessionHandle==dummySession2);
1.189 + TEST(shapeEntry->iHandleRefList->iNext->iRefCount==1);
1.190 +
1.191 + //now decrement an instance from this session(DELETE FIRST ENTRY)
1.192 + TEST(shapeEntry->DecRefCount(dummySession)==KErrNone);
1.193 + TEST(shapeEntry->iHandleRefCount==2);
1.194 + TEST(shapeEntry->iHandleRefList->iNext->iRefCount==1);
1.195 + TEST(shapeEntry->DecRefCount(dummySession)==KErrNone);
1.196 + TEST(shapeEntry->iHandleRefCount==1);
1.197 + TEST(shapeEntry->iHandleRefList->iRefCount==1);
1.198 + TEST(shapeEntry->iHandleRefList->iSessionHandle=dummySession2);
1.199 +
1.200 + //now add another session to this list
1.201 + TInt dummySession3=14;
1.202 + TEST(shapeEntry->IncRefCount(dummySession3)==KErrNone);
1.203 + TEST(shapeEntry->iHandleRefCount==2);
1.204 + //test delete this last entry in the list(DELETE LAST ENTRY)
1.205 + TEST(shapeEntry->DecRefCount(dummySession3)==KErrNone);
1.206 + TEST(shapeEntry->iHandleRefCount==1);
1.207 + TEST(shapeEntry->iHandleRefList->iRefCount==1);
1.208 + TEST(shapeEntry->iHandleRefList->iSessionHandle==dummySession2);
1.209 +
1.210 +
1.211 + //test Dec on non-existent session
1.212 + TEST(shapeEntry->DecRefCount(100)==KErrNotFound);
1.213 +
1.214 + COpenFontShaperCacheEntry::Delete(&User::Heap(),shapeEntry);
1.215 + delete shapeHeader;
1.216 +
1.217 + __UHEAP_MARKEND;
1.218 + }
1.219 +
1.220 +/**
1.221 + @SYMTestCaseID
1.222 + GRAPHICS-FNTSTORE-0045
1.223 +
1.224 + @SYMTestCaseDesc
1.225 + Tests the shaper cache APIs.
1.226 +
1.227 + @SYMTestActions
1.228 + 1. Creates a dummy TShapeHeader object that will be cached and reused through the test.
1.229 + 2. Gets some memory to pass back the results. It needs to be big enough for a TShapeHeader
1.230 + object plus 10 bytes for every glyph returned.
1.231 + 3. Finds or creates four font file objects to support a font file.
1.232 + 4. Gets the number of supported typefaces.
1.233 + 5. Creates a font.
1.234 + 6. Gets a COpenFont object.
1.235 + 7. For COpenFonts it attempts to put this into the shaper cache and test if it was successful.
1.236 + 8. Calls DeleteShape to decrement the reference count.
1.237 + 9. Changes the shaped data slightly to make it into a new shaped data and insert into the
1.238 + cache as a new entry.
1.239 + 10. Tests if the LRU cache is working by seeing if the first entry in the cache is the newest one.
1.240 + 11. Calls DeleteShape to decrement the reference count
1.241 + 12. Calls the GetShapedData API and tests the returned TShapeHeader. Also checks if the returned
1.242 + cache entry is at the top of the cache.
1.243 + 13. Searches the cache for the first entry using the GetShapedData API.
1.244 + 14. Calls DeleteShape to decrement the reference count.
1.245 + 15. Brings the end value back to its original value.
1.246 + 16. Fills the cache and then tests replacement policy by attempting to add a new entry.
1.247 + 17. Prepares a raw input data structure.
1.248 + 18. Keeps inserting pseudo-new shaped entries into the cache to fill it up.
1.249 + 19. Changes the cached entries slightly to distinguish between each entry.
1.250 + 20. Tries to add a new entry and checks that the entry replaced was the last entry in the cache.
1.251 + 21. Calculates the memory needed for the new entry.
1.252 + 22. Calculates the memory that will be freed to accommodate the new entry and the
1.253 + position of the last entry in the cache once deletion is done.
1.254 + 23. Finds the glyphcount of the expected new last entry in the cache.
1.255 + 24. Does the insertion and tests.
1.256 + 25. Calls DeleteShape to decrement the reference count.
1.257 + 26. Calculates the memory occupied by the last entry in the cache. This is the memory that will
1.258 + be released when the last entry is deleted.
1.259 + 27. Tests with multiple open fonts with caches. Creates the new font.
1.260 + 28. Does the testing only if the font is a COpenFont.
1.261 + 29. Attempts to put a new entry into the second shaper cache and test if it was successful.
1.262 + 30. Creates a pseudo-new shape header to put into the cache of this new open font.
1.263 + 31. Inserst an entry into the cache.
1.264 + 32. Tests cache memory freeing policy, i.e. delete from all other caches except the current one.
1.265 + 33. Finds out how much memory needs freeing, i.e. how much was just added.
1.266 + 34. Tries to free memory from the original open font cache. The result should be that
1.267 + memory should be freed from openFont2 cache, and not openFont cache.
1.268 + 35. Checks
1.269 + a) if the memory used by openFont2 cache has reduced, i.e. back to original memory.
1.270 + b) if the last entry from openFont2 cache has been deleted.
1.271 + c) last entry from openFont cache is intact.
1.272 + 36. Cleans up font2, font1 and removes all fonts.
1.273 +
1.274 + @SYMTestExpectedResults
1.275 + All tests shall pass.
1.276 +
1.277 +*/
1.278 +void CTShaperCache::TestShaperCacheAPIsL()
1.279 + {
1.280 + INFO_PRINTF1(_L("The following results are for shaper cache API tests\n"));
1.281 +
1.282 + // Create a dummy TShapeHeader object that will be cached, and reused all through this test
1.283 + TShapeHeader* shape = 0;
1.284 +
1.285 + // get some memory to pass back the results,
1.286 + // This needs to be big enough for a TShapeHeader
1.287 + // plus 10 bytes for every glyph returned (-1 for the 1 byte allocated in TShapeHeader for iBuffer)
1.288 + shape = reinterpret_cast<TShapeHeader*>( iHeap->AllocL(sizeof(TShapeHeader) + (KResultNumberOfGlyphs * 10) + 3) );
1.289 +
1.290 + // get the results into the shaper structure 'shape'
1.291 + shape->iGlyphCount = KResultNumberOfGlyphs;
1.292 + shape->iCharacterCount = 8;
1.293 + shape->iReserved0 = 0;
1.294 + shape->iReserved1 = 0;
1.295 +
1.296 + // iBuffer contains 10 bytes for every glyph
1.297 + // the glyph code (4 bytes), position X(2 bytes) Y(2 bytes) and indices(2 bytes)
1.298 + // first is glyph count * 4 byte glyph codes
1.299 + TUint32* glyphOut = reinterpret_cast<TUint32*>(shape->iBuffer);
1.300 + TInt16* posOut = reinterpret_cast<TInt16*>(shape->iBuffer +
1.301 + (4 * KResultNumberOfGlyphs));
1.302 + TInt16* indicesOut = reinterpret_cast<TInt16*>(shape->iBuffer +
1.303 + (8 * KResultNumberOfGlyphs) + 4);
1.304 +
1.305 + *glyphOut++ = (TUint32)1461;
1.306 + *posOut++ = (TInt16)0;
1.307 + *posOut++ = (TInt16)0;
1.308 + *indicesOut++ = (TInt16)0;
1.309 +
1.310 + *glyphOut++ = (TUint32)1778;
1.311 + *posOut++ = (TInt16)12;
1.312 + *posOut++ = (TInt16)0;
1.313 + *indicesOut++ = (TInt16)7;
1.314 +
1.315 + *glyphOut++ = (TUint32)1550;
1.316 + *posOut++ = (TInt16)16;
1.317 + *posOut++ = (TInt16)0;
1.318 + *indicesOut++ = (TInt16)3;
1.319 +
1.320 + *glyphOut++ = (TUint32)1362;
1.321 + *posOut++ = (TInt16)28;
1.322 + *posOut++ = (TInt16)0;
1.323 + *indicesOut++ = (TInt16)7;
1.324 +
1.325 + // There is an extra pair of positions: this is the total advance
1.326 + posOut[0] = (TInt16)28;
1.327 + posOut[1] = (TInt16)0;
1.328 +
1.329 + TFontShapeFunctionParameters* params;
1.330 + params = reinterpret_cast<TFontShapeFunctionParameters*>( iHeap->AllocL(sizeof(TFontShapeFunctionParameters)));
1.331 + params->iEnd = 8;
1.332 + params->iLanguage = 0;
1.333 + params->iScript = KDevanagariScriptCode;
1.334 + params->iStart = 0;
1.335 + //TBufC16<9> text(KTextToShape);
1.336 + params->iText = &KTextToShape();
1.337 +
1.338 + // Add fonts
1.339 + TUid id1 = iFontStore->AddFileL(KFontDummy);
1.340 + TUid id2 = iFontStore->AddFileL(KFontDummy_b);
1.341 + TUid id3 = iFontStore->AddFileL(KFontDummy_i);
1.342 + TUid id4 = iFontStore->AddFileL(KFontDummy_bi);
1.343 +
1.344 + INFO_PRINTF1(_L("SHAPER CACHE API TESTS SET 1: Testing cache with a single COpentFont cache"));
1.345 +
1.346 + TInt typefaces = iFontStore->NumTypefaces();
1.347 + TInt typeface = 0;
1.348 + TInt height = 12;
1.349 +
1.350 + TTypefaceSupport support;
1.351 + iFontStore->TypefaceSupport(support,typeface);
1.352 + TFontSpec fs;
1.353 + fs.iTypeface = support.iTypeface;
1.354 +
1.355 + INFO_PRINTF3(_L("Typeface is %d and height is %d"), typeface, height);
1.356 + //Create a font
1.357 + CFont* font = NULL;
1.358 + fs.iHeight = iFontStore->FontHeightInTwips(typeface,height);
1.359 + // get a COpenFont object
1.360 + iFontStore->GetNearestFontToDesignHeightInPixels(font, fs);
1.361 + CleanupStack::PushL(font);
1.362 +
1.363 +
1.364 + // Do the testing only if the font is a COpenFont
1.365 + COpenFont* openFont = NULL;
1.366 + CShaper::TInput input;
1.367 + if (((CBitmapFont*)font)->IsOpenFont())
1.368 + {
1.369 + __UHEAP_MARK;
1.370 + openFont = ((CBitmapFont*)font)->OpenFont();
1.371 +
1.372 + /***************************First Test***************************
1.373 + Attempt to put this into the shaper cache and then delete it. Test if it was successful
1.374 + */
1.375 + TShapeHeader* cached_header = openFont->InsertShapedDataIntoCache(0,params, shape);
1.376 +
1.377 + INFO_PRINTF1(_L("SHAPER CACHE API TEST 1: Simple cache insertion test"));
1.378 + TEST(cached_header != NULL && openFont->GetGlyphCache()->iNumberOfShaperCacheEntries == 2);
1.379 +
1.380 + /* Call DeleteShape to decrement the reference count */
1.381 + ((CBitmapFont*)font)->DeleteShape(0, cached_header);
1.382 +
1.383 + // Now delete this data
1.384 + openFont->FreeShaperCacheMemory(openFont->GetGlyphCache()->iShapingInfoCacheMemory);
1.385 + TEST(openFont->GetGlyphCache()->iNumberOfShaperCacheEntries == 1);
1.386 + // Put the shaped data back into the cache to continue with testing
1.387 + cached_header = openFont->InsertShapedDataIntoCache(0,params, shape);
1.388 + TEST(cached_header != NULL && openFont->GetGlyphCache()->iNumberOfShaperCacheEntries == 2);
1.389 + ((CBitmapFont*)font)->DeleteShape(0, cached_header);
1.390 +
1.391 + /**************************Second Test**************************
1.392 + Now change the shaped data slightly to make it into a new shaped data and insert into the
1.393 + cache as a new entry
1.394 + */
1.395 + shape->iGlyphCount++;
1.396 + params->iEnd++;
1.397 + TShapeHeader* cached_header2 = openFont->InsertShapedDataIntoCache(0,params, shape);
1.398 +
1.399 + /* Now test if the LRU cache is working by seeing if the first entry in the cache is the newest one */
1.400 + COpenFontGlyphCache* glyphCache = openFont->GetGlyphCache();
1.401 +
1.402 + INFO_PRINTF1(_L("SHAPER CACHE API TEST 2: Test the LRU (Least Recently Used) cache structure"));
1.403 + TEST(glyphCache->iShaperCacheSentinel->iNext->iShapeHeader->iGlyphCount == KResultNumberOfGlyphs + 1);
1.404 +
1.405 + /* Call DeleteShape to decrement the reference count */
1.406 + ((CBitmapFont*)font)->DeleteShape(0, cached_header2);
1.407 +
1.408 +
1.409 + /**************************Third Test**************************
1.410 + Call the GetShapedData API and test the returned TShapeHeader, and also check if the returned
1.411 + cache entry is now at the top of the cache
1.412 + */
1.413 +
1.414 + /* Now search the cache for the first entry using the GetShapedData API */
1.415 + params->iEnd --;
1.416 + TInt expectedGlyphCount = glyphCache->iShaperCacheSentinel->iPrevious->iShapeHeader->iGlyphCount;
1.417 + TShapeHeader* searchedCachedHeader = openFont->GetShapedData(0,params);
1.418 +
1.419 + INFO_PRINTF1(_L("SHAPER CACHE API TEST 3: GetShapedData API test"));
1.420 + TEST(searchedCachedHeader->iGlyphCount == expectedGlyphCount &&
1.421 + searchedCachedHeader->iGlyphCount ==glyphCache->iShaperCacheSentinel->iNext->iShapeHeader->iGlyphCount);
1.422 +
1.423 + /* Call DeleteShape to decrement the reference count */
1.424 + ((CBitmapFont*)font)->DeleteShape(0, searchedCachedHeader);
1.425 +
1.426 + /* Bring the end value back to its original value */
1.427 + params->iEnd ++;
1.428 +
1.429 +
1.430 + /**************************Fourth Test**************************
1.431 + Fill the cache and then test replacement policy by attempting to add a new entry
1.432 + */
1.433 +
1.434 + /* First prepare a raw input data structure */
1.435 + TInt memoryUsed = 0;
1.436 + input.iText = &KTextToShape();
1.437 + input.iStart = 0;
1.438 + input.iEnd = params->iEnd;
1.439 + input.iScript= KDevanagariScriptCode;
1.440 + input.iLanguage = 0;
1.441 + input.iMaximumAdvance = KMaxTInt;
1.442 + input.iFlags = 0;
1.443 + input.iSessionHandle = 0;
1.444 + input.iReserved1 = 0;
1.445 + TInt addedBytes = 0;
1.446 + TShapeHeader* chached_header3 = 0;
1.447 + openFont->FreeShaperCacheMemory(KMaxShaperSesssionCacheMemory);
1.448 + openFont->File()->GetFontStore()->SetShaperCacheMemUsage(0);
1.449 + RArray<TInt> cacheMemUsage;
1.450 + /* Keep inserting pseudo-new shaped entries into the cache to fill it up */
1.451 + while(openFont->File()->GetFontStore()->GetShaperCacheMemUsage() < KMaxShaperSesssionCacheMemory)
1.452 + {
1.453 + memoryUsed = openFont->File()->GetFontStore()->GetShaperCacheMemUsage();
1.454 + // Change the cached entries slightly to distinguish between each entry
1.455 + shape->iGlyphCount++;
1.456 + input.iEnd++;
1.457 + chached_header3 = glyphCache->Insert(0,iHeap, input, shape, addedBytes);
1.458 + if (chached_header3 != NULL)
1.459 + openFont->File()->GetFontStore()->SetShaperCacheMemUsage(memoryUsed + addedBytes);
1.460 + ((CBitmapFont*)font)->DeleteShape(0, chached_header3);
1.461 + cacheMemUsage.AppendL(openFont->File()->GetFontStore()->GetShaperCacheMemUsage() - memoryUsed);
1.462 + chached_header3 = NULL;
1.463 + }
1.464 +
1.465 + /* Now try to add a new entry, and check that the entry replaced was the last entry in the cache */
1.466 + TInt last_entry_glyph_count = glyphCache->iShaperCacheSentinel->iPrevious->iShapeHeader->iGlyphCount;
1.467 + shape->iGlyphCount++;
1.468 + input.iEnd++;
1.469 + params->iEnd = input.iEnd;
1.470 +
1.471 + /* Calculate the memory needed for the new entry */
1.472 +
1.473 +
1.474 + TInt heapSizeBefAloc = 0;
1.475 + iHeap->AllocSize(heapSizeBefAloc);
1.476 + COpenFontShaperCacheEntry *tempEntry = COpenFontShaperCacheEntry::New(iHeap, input, shape);
1.477 + TInt heapSizeAftAloc = 0;
1.478 + iHeap->AllocSize(heapSizeAftAloc);
1.479 + TInt bytes_needed = heapSizeAftAloc - heapSizeBefAloc;
1.480 + COpenFontShaperCacheEntry::Delete(iHeap, tempEntry);
1.481 +
1.482 + TInt bytesToDelete = 0;
1.483 +
1.484 + COpenFontShaperCacheEntry* previous = glyphCache->iShaperCacheSentinel->iPrevious;
1.485 + /* Calculate the memory that will be freed to accommodate the new entry,
1.486 + and the position of the last entry in the cache once deletion is done */
1.487 + TInt index = 0;
1.488 + while (bytesToDelete <= bytes_needed)
1.489 + {
1.490 +
1.491 + bytesToDelete += cacheMemUsage[index++];
1.492 + previous = previous->iPrevious;
1.493 + }
1.494 + cacheMemUsage.Close();
1.495 + /* Find the glyphcount of the expected new last entry in the cache */
1.496 + expectedGlyphCount = previous->iShapeHeader->iGlyphCount;
1.497 +
1.498 + /* Finally, do the insertion, and test */
1.499 + TShapeHeader* cached_header4 = openFont->InsertShapedDataIntoCache(0, params, shape);
1.500 +
1.501 + INFO_PRINTF1(_L("SHAPER CACHE API TEST 4: LRU cache replacement policy test"));
1.502 + TEST(glyphCache->iShaperCacheSentinel->iPrevious->iShapeHeader->iGlyphCount == expectedGlyphCount);
1.503 +
1.504 + /* Call DeleteShape to decrement the reference cout */
1.505 + ((CBitmapFont*)font)->DeleteShape(0, cached_header4);
1.506 +
1.507 +
1.508 + /**************************Fifth Test**************************
1.509 + Simply test the FreeShaperCacheMemory API
1.510 + */
1.511 +
1.512 + /* Calculate the memory of occupied by the last entry in the cache. This is the memory that will
1.513 + be released when the last entry is deleted
1.514 + */
1.515 + last_entry_glyph_count = glyphCache->iShaperCacheSentinel->iPrevious->iShapeHeader->iGlyphCount;
1.516 + TInt bufferSize = (sizeof(TUint32) + sizeof(TInt16) + sizeof(TInt16) * 2)
1.517 + * last_entry_glyph_count + sizeof(TInt16) * 2;
1.518 +
1.519 + bytes_needed = bufferSize + sizeof(COpenFontShaperCacheEntry) +
1.520 + sizeof(TShapeHeader) + sizeof(TUint16)*input.iText->Length();
1.521 +
1.522 + memoryUsed = openFont->File()->GetFontStore()->GetShaperCacheMemUsage();
1.523 + expectedGlyphCount = glyphCache->iShaperCacheSentinel->iPrevious->iPrevious->iShapeHeader->iGlyphCount;
1.524 + TInt memoryReleased = openFont->FreeShaperCacheMemory(bytes_needed);
1.525 +
1.526 + INFO_PRINTF1(_L("SHAPER CACHE API TEST 5: FreeShaperCacheMemory API test\n"));
1.527 + TEST(openFont->File()->GetFontStore()->GetShaperCacheMemUsage() == memoryUsed - memoryReleased &&
1.528 + glyphCache->iShaperCacheSentinel->iPrevious->iShapeHeader->iGlyphCount == expectedGlyphCount);
1.529 +
1.530 + __UHEAP_MARKEND;
1.531 + }
1.532 +
1.533 + INFO_PRINTF1(_L("SHAPER CACHE API TESTS SET 2: Testing cache with a two COpentFont caches"));
1.534 + /* Now test with multiple open fonts with caches */
1.535 + /* Create the new font */
1.536 + height = 4;
1.537 + iFontStore->TypefaceSupport(support,typeface);
1.538 + fs.iTypeface = support.iTypeface;
1.539 +
1.540 + INFO_PRINTF3(_L("Typeface is %d and height is %d"), typeface, height);
1.541 +
1.542 + CFont* font2 = NULL;
1.543 + fs.iHeight = iFontStore->FontHeightInTwips(typeface,height);
1.544 + iFontStore->GetNearestFontToDesignHeightInPixels(font2, fs);
1.545 + CleanupStack::PushL(font2);
1.546 +
1.547 + COpenFont* openFont2;
1.548 + /* Do the testing only if the font is a COpenFont */
1.549 + if (((CBitmapFont*)font2)->IsOpenFont())
1.550 + {
1.551 + __UHEAP_MARK;
1.552 + openFont2 = ((CBitmapFont*)font2)->OpenFont();
1.553 +
1.554 + /***************************Sixth Test***************************
1.555 + Attempt to put a new entry into the second shaper cache and test if it was successful
1.556 + */
1.557 +
1.558 + /* Create a pseudo-new shape header to put into the cache of this new open font */
1.559 + shape->iGlyphCount++;
1.560 + params->iEnd++;
1.561 +
1.562 + /* Insert an entry into the cache */
1.563 + TShapeHeader* cached_header5 = openFont2->InsertShapedDataIntoCache(0, params, shape);
1.564 + ((CBitmapFont*)font2)->DeleteShape(0, cached_header5);
1.565 +
1.566 + INFO_PRINTF1(_L("SHAPER CACHE API TEST 6: Second cache insertion test"));
1.567 + TEST(cached_header5 != NULL && openFont2->GetGlyphCache()->iNumberOfShaperCacheEntries == 2);
1.568 +
1.569 + /***************************Seventh, Eighth and Ninth Tests***************************
1.570 + Test cache memory freeing policy, i.e. delete from all other caches except the current one
1.571 + */
1.572 +
1.573 + /* First find out how much memory needs freeing, i.e. how much was just added */
1.574 + TInt bufferSize = (sizeof(TUint32) + sizeof(TInt16) + sizeof(TInt16) * 2)
1.575 + * shape->iGlyphCount + sizeof(TInt16) * 2;
1.576 +
1.577 + TInt bytes_needed = bufferSize + sizeof(COpenFontShaperCacheEntry) +
1.578 + sizeof(TShapeHeader) + sizeof(TUint16)*input.iText->Length();
1.579 +
1.580 +
1.581 + /* Now try to free memory from the original open font cache. The result should be that
1.582 + memory should be freed from openFont2 cache, and not openFont cache
1.583 + */
1.584 + TInt memoryUsed = openFont2->GetGlyphCache()->iShapingInfoCacheMemory;
1.585 + TInt expectedGlyphCount = openFont->GetGlyphCache()->iShaperCacheSentinel->iPrevious->iShapeHeader->iGlyphCount;
1.586 + TInt deletedMemory = openFont->FreeShaperCacheMemory(bytes_needed);
1.587 +
1.588 + /* Now check:
1.589 + a) if the memory used by openFont2 cache has reduced, i.e. back to original memory
1.590 + b) if the last entry from openFont2 cache has been deleted
1.591 + c) last entry from openFont cache is intact
1.592 + */
1.593 + INFO_PRINTF1(_L("SHAPER CACHE API TEST 7: Test if memory is freed from second COpenFont"));
1.594 + TEST(memoryUsed - openFont2->GetGlyphCache()->iShapingInfoCacheMemory == deletedMemory &&
1.595 + openFont2->GetGlyphCache()->iShapingInfoCacheMemory == 0);
1.596 +
1.597 + INFO_PRINTF1(_L("SHAPER CACHE API TEST 8: Test if last entry of second COpenFont is deleted"));
1.598 + TEST(openFont2->GetGlyphCache()->iNumberOfShaperCacheEntries == 1);
1.599 +
1.600 + INFO_PRINTF1(_L("SHAPER CACHE API TEST 9: Test if the last entry of the first COpenFont is intact"));
1.601 + TEST(openFont->GetGlyphCache()->iShaperCacheSentinel->iPrevious->iShapeHeader->iGlyphCount == expectedGlyphCount);
1.602 +
1.603 + /***********************************Tenth Tests*****************************************
1.604 + Test cache memory consistency and that there are no leakages when deleting memory from the cache
1.605 + */
1.606 +
1.607 + /* Continue adding entries to second open font cache until the memory used by the first one
1.608 + goes down to zero, at which point the number of cache entries should be 1, and memory from
1.609 + the current open font should start getting released and eventually reach 0 when the number
1.610 + of cached entries reaches 1.
1.611 + */
1.612 + TShapeHeader* cached_header6 = NULL;
1.613 + /* Keep inserting pseudo-new shaped entries into the cache to fill it up */
1.614 + while(openFont->GetGlyphCache()->iNumberOfShaperCacheEntries > 1)
1.615 + {
1.616 + memoryUsed = openFont2->File()->GetFontStore()->GetShaperCacheMemUsage();
1.617 + // Change the cached entries slightly to distinguish between each entry
1.618 + shape->iGlyphCount++;
1.619 + params->iEnd++;
1.620 + cached_header6 = openFont2->InsertShapedDataIntoCache(0, params, shape);
1.621 + ((CBitmapFont*)font2)->DeleteShape(0, cached_header6);
1.622 + cached_header6 = NULL;
1.623 + }
1.624 +
1.625 + INFO_PRINTF1(_L("SHAPER CACHE API TEST 10: Test consistency of cache memory"));
1.626 + TEST(openFont->GetGlyphCache()->iShapingInfoCacheMemory == 0);
1.627 +
1.628 +
1.629 + /**
1.630 + @SYMTestCaseID GRAPHICS-SYSLIB-FNTSTORE-UT-4001
1.631 + @SYMTestCaseDesc Test that when trying to delete a shape not in the cache it
1.632 + does not loop infinitely trying to find it.
1.633 + @SYMTestPriority Medium
1.634 + @SYMTestActions Pass a null shape header to the DeleteShape function.
1.635 + @SYMTestExpectedResults The function call should return instead of looping infinitely.
1.636 + @SYMDEF PDEF125354
1.637 + */
1.638 + ((CTShaperCacheStep*)iStep)->RecordTestResultL();
1.639 + ((CTShaperCacheStep*)iStep)->SetTestStepID(_L("GRAPHICS-SYSLIB-FNTSTORE-UT-4001"));
1.640 + INFO_PRINTF1(_L("SHAPER CACHE API TEST 11: Test that shape not found does not loop infinitely."));
1.641 + TShapeHeader* null_header = NULL;
1.642 + // Timeout set in TEF script to catch infinite loop.
1.643 + ((CBitmapFont*)font2)->DeleteShape(0, null_header);
1.644 +
1.645 + ((CTShaperCacheStep*)iStep)->CloseTMSGraphicsStep();
1.646 + __UHEAP_MARKEND;
1.647 + }
1.648 +
1.649 + /* Cleanup font2*/
1.650 + CleanupStack::Pop(font2);
1.651 + iFontStore->ReleaseFont(font2);
1.652 +
1.653 + /* Cleanup font1 */
1.654 + CleanupStack::Pop(font);
1.655 + iFontStore->ReleaseFont(font);
1.656 +
1.657 + // Remove the fonts
1.658 + iFontStore->RemoveFile(id1);
1.659 + iFontStore->RemoveFile(id2);
1.660 + iFontStore->RemoveFile(id3);
1.661 + iFontStore->RemoveFile(id4);
1.662 + }
1.663 +
1.664 +void CTShaperCache::RunTestCaseL(TInt aCurTestCase)
1.665 + {
1.666 + ((CTShaperCacheStep*)iStep)->SetTestStepID(KUnknownSYMTestCaseIDName);
1.667 + switch(aCurTestCase)
1.668 + {
1.669 + case 1:
1.670 + ((CTShaperCacheStep*)iStep)->SetTestStepID(_L("GRAPHICS-FNTSTORE-0043"));
1.671 + INFO_PRINTF1(_L("#################### T_SHAPERCACHE test case 1 ########################\n"));
1.672 + TRAPD(err,Test1L());
1.673 + TEST(err == KErrNone);
1.674 + break;
1.675 + case 2:
1.676 + ((CTShaperCacheStep*)iStep)->SetTestStepID(_L("GRAPHICS-FNTSTORE-0044"));
1.677 + INFO_PRINTF1(_L("#################### T_SHAPERCACHE test case 2 ########################\n"));
1.678 + TRAP(err,Test2L());
1.679 + TEST(err == KErrNone);
1.680 + break;
1.681 + case 3:
1.682 + ((CTShaperCacheStep*)iStep)->SetTestStepID(_L("GRAPHICS-FNTSTORE-0045"));
1.683 + INFO_PRINTF1(_L("#################### T_SHAPERCACHE test case 3 ########################"));
1.684 + TRAP(err,TestShaperCacheAPIsL());
1.685 + TEST(err == KErrNone);
1.686 + break;
1.687 + case 4:
1.688 + ((CTShaperCacheStep*)iStep)->SetTestStepID(KNotATestSYMTestCaseIDName);
1.689 + ((CTShaperCacheStep*)iStep)->CloseTMSGraphicsStep();
1.690 + TestComplete();
1.691 + break;
1.692 + }
1.693 + ((CTShaperCacheStep*)iStep)->RecordTestResultL();
1.694 + }
1.695 +
1.696 +
1.697 +//--------------
1.698 +__CONSTRUCT_STEP__(ShaperCache)
1.699 +
1.700 +
1.701 +