fbs/fontandbitmapserver/tfbs/tfonttableandglyph.cpp
changeset 36 01a6848ebfd7
child 45 36b2e23a8629
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fbs/fontandbitmapserver/tfbs/tfonttableandglyph.cpp	Fri Apr 16 16:21:04 2010 +0300
@@ -0,0 +1,771 @@
+// Copyright (c) 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:
+//
+
+#include <gdi.h>
+#include <fbs.h> 
+#include <e32test.h>
+#include <e32property.h>
+#include <graphics/openfontconstants.h>
+#include <graphics/openfontrasterizer.h>
+#include <graphics/gdi/gdiplatapi.h>
+#include "fbsmessage.h"
+#include "tfonttableandglyph.h"
+
+//global variable
+_LIT16(KTestFontFile, "C:\\DejaVuSans.ttf");
+_LIT16(KTestFontFaceName, "DejaVu Sans");
+
+_LIT16(KTestFontFile2, "C:\\DejaVuSerif.ttf");
+_LIT16(KTestFontFaceName2, "DejaVu Serif");
+
+static void LoadOpenFontLibraries(CFontStore* aFontStore);
+
+LOCAL_C const TInt KFontHeight = 12;
+LOCAL_C const TInt KInvalidGlyphId = 0xffff;
+
+CTFontAndGlyph::CTFontAndGlyph(CTestStep* aStep) :
+    CTGraphicsBase(aStep),
+    iBmp(NULL),
+    iBmp2(NULL),
+    iDevice(NULL),
+    iDevice2(NULL),
+    iFont(NULL),
+    iFont2(NULL),
+    iFontStore(NULL),
+    iFontSpec(KTestFontFaceName, KFontHeight),
+    iFontSpec2(KTestFontFaceName2, KFontHeight)
+    {
+        // a null constructor
+    }
+
+CTFontAndGlyph::~CTFontAndGlyph()
+    {
+    CleanEnv();
+    }
+
+void CTFontAndGlyph::RunTestCaseL(TInt aCurTestCase)
+    {
+    ((CTFontAndGlyphStep*)iStep)->SetTestStepID(KUnknownSYMTestCaseIDName);
+    
+    switch(aCurTestCase)
+        {
+    case 1:
+        ((CTFontAndGlyphStep*)iStep)->SetTestStepID(_L("TI18N-GDI-CIT-4079"));
+        INFO_PRINTF1(_L("GetHintedGlyphById"));
+        GetHintedGlyphById(); 
+        break;
+        
+    case 2:
+        ((CTFontAndGlyphStep*)iStep)->SetTestStepID(_L("TI18N-GDI-CIT-4080"));
+        INFO_PRINTF1(_L("GetUnHintedGlyphById"));
+        GetUnHintedGlyphById();
+        break;
+               
+    case 3:
+        ((CTFontAndGlyphStep*)iStep)->SetTestStepID(_L("TI18N-GDI-CIT-4081"));
+        INFO_PRINTF1(_L("GetHintedGlyphByWrongId"));
+        GetHintedGlyphByWrongId();
+        break;   
+        
+    case 4:
+        ((CTFontAndGlyphStep*)iStep)->SetTestStepID(_L("TI18N-GDI-CIT-4082"));
+        INFO_PRINTF1(_L("GetGlyphWithNoMem"));
+        GetGlyphWithNoMem();
+        break; 
+        
+    case 5:
+        ((CTFontAndGlyphStep*)iStep)->SetTestStepID(_L("TI18N-GDI-CIT-4083"));
+        INFO_PRINTF1(_L("GetFontTable"));
+        GetFontTable();
+        break;         
+        
+        
+    case 6:
+        ((CTFontAndGlyphStep*)iStep)->SetTestStepID(_L("TI18N-GDI-CIT-4084"));
+        INFO_PRINTF1(_L("GetFontTableByWrongTag"));
+        GetFontTableByWrongTag();
+        break;        
+
+    case 7:
+        ((CTFontAndGlyphStep*)iStep)->SetTestStepID(_L("TI18N-GDI-CIT-4085"));
+        INFO_PRINTF1(_L("GetFontTableWithNoMem"));
+        GetFontTableWithNoMem();
+        break;    
+        
+    case 8:
+        ((CTFontAndGlyphStep*)iStep)->SetTestStepID(_L("TI18N-GDI-CIT-4089"));
+        INFO_PRINTF1(_L("GlyphOutlineIteratorPanics"));
+        GlyphOutlineIteratorPanics();
+        break;   
+        
+    case 9:
+        ((CTFontAndGlyphStep*)iStep)->SetTestStepID(_L("TI18N-GDI-CIT-4090"));
+        INFO_PRINTF1(_L("WDPAndSMPSafeTest"));
+        SMPAndWDPSafeTest();
+        break;
+        
+    case 10:
+        ((CTFontAndGlyphStep*)iStep)->SetTestStepID(_L("TI18N-GDI-CIT-4087"));
+        INFO_PRINTF1(_L("TestFbsFontHandleIsZeroForFont"));
+        TestFbsFontHandleIsZeroForFont();
+        break;  
+
+    case 11:
+        ((CTFontAndGlyphStep*)iStep)->SetTestStepID(_L("TI18N-GDI-CIT-4088"));
+        INFO_PRINTF1(_L("TestFbsFontHandleIsZeroForGlyph"));
+        TestFbsFontHandleIsZeroForGlyph();
+        break;   
+        
+    case 12:
+        ((CTFontAndGlyphStep*)iStep)->SetTestStepID(KNotATestSYMTestCaseIDName);
+        ((CTFontAndGlyphStep*)iStep)->CloseTMSGraphicsStep();
+        TestComplete();
+        break;
+    default:
+        INFO_PRINTF1(_L("Invalid test case id found."));
+        }    
+        ((CTFontAndGlyphStep*)iStep)->RecordTestResultL();
+    }
+
+
+/**
+    @SYMTestCaseID    TI18N-GDI-CIT-4083
+    @SYMTestCaseDesc    Get font table. 
+    @SYMTestActions    Get font table using the new RFontTable class and test
+    the return value.
+    @SYMTestExpectedResults  Open() returns KErrNone. TableContent returns the
+    table content. 
+*/
+void CTFontAndGlyph::GetFontTable()
+    {
+    __UHEAP_MARK;
+    RFontTable fontTable;
+    TInt err = fontTable.Open(*iFont, 0x68656164);  
+    TEST(err == KErrNone);
+    TUint32* tablePtr = (TUint32*)fontTable.TableContent();     
+    TEST(tablePtr != NULL);
+    TEST(tablePtr[3] == 0xF53C0F5F);   //magic number is correct
+    RFontTable fontTableInCache;
+    err = fontTableInCache.Open(*iFont, 0x68656164);  
+    TEST(err == KErrNone);
+    TUint32* tablePtr2 = (TUint32*)fontTableInCache.TableContent();  
+    TEST(tablePtr2[3] == 0xF53C0F5F);
+    TEST(tablePtr == tablePtr2);
+    
+    RFontTable fontTable2;
+    err = fontTable2.Open(*iFont2, 0x68656164);  
+    TEST(err == KErrNone);
+    tablePtr = (TUint32*)fontTable2.TableContent();     
+    TEST(tablePtr != NULL);
+    TEST(tablePtr[3] == 0xF53C0F5F);   //magic number is correct
+    RFontTable fontTableInCache2;
+    err = fontTableInCache2.Open(*iFont2, 0x68656164);  
+    TEST(err == KErrNone);
+    tablePtr2 = (TUint32*)fontTableInCache2.TableContent();  
+    TEST(tablePtr2[3] == 0xF53C0F5F);
+    TEST(tablePtr == tablePtr2);
+    
+    fontTableInCache.Close();
+    fontTable.Close();
+    fontTableInCache2.Close();
+    fontTable2.Close();
+    __UHEAP_MARKEND;
+    }
+
+
+/**
+    @SYMTestCaseID    TI18N-GDI-CIT-4084
+    @SYMTestCaseDesc    Get font table, providing an invalid tag. 
+    @SYMTestActions    Get font table, providing an invalid tag (0). 
+    Test the return value.
+    @SYMTestExpectedResults    Open() returns KErrNotFound.
+*/
+void CTFontAndGlyph::GetFontTableByWrongTag()
+    {
+    __UHEAP_MARK;
+    RFontTable fontTableForWrongID;
+    TInt err = fontTableForWrongID.Open(*iFont, 0);  
+    fontTableForWrongID.Close(); 
+    TEST(KErrNotFound == err); 
+    __UHEAP_MARKEND;
+    }
+
+
+/**
+    @SYMTestCaseID    TI18N-GDI-CIT-4085
+    @SYMTestCaseDesc    Get font table, when system is OOM. 
+    @SYMTestActions    Get font table, simulate OOM conditions using debug macros,
+     and test return value.
+    @SYMTestExpectedResults    Open() returns KErrNoMemory. TableContent() and 
+    TableLength() return NULL/0.
+*/
+void CTFontAndGlyph::GetFontTableWithNoMem()
+    {
+#ifdef _DEBUG 
+    __UHEAP_MARK;
+    RFontTable aFontTableForMem;
+    RFbsSession *fbsSession = RFbsSession::GetSession();
+    fbsSession->SendCommand(EFbsMessSetHeapFail, RFbsSession::EHeapFailTypeHeapMemory, 1);
+    TInt err = aFontTableForMem.Open(*iFont, 0x68656164); /* 'head' in ascii (hex) */
+    TEST(KErrNoMemory == err);
+    TEST(0 == aFontTableForMem.TableLength());
+    TEST(0 == aFontTableForMem.TableContent());
+    aFontTableForMem.Close();
+    fbsSession->SendCommand(EFbsMessSetHeapReset, RFbsSession::EHeapFailTypeHeapMemory);
+    __UHEAP_MARKEND;
+#else
+    INFO_PRINTF1(_L("Skipping test GetFontTableWithNoMem in release mode")); 
+#endif
+    }
+
+
+/**
+    @SYMTestCaseID    TI18N-GDI-CIT-4082
+    @SYMTestCaseDesc    Get glyph outline when system is out of memory.
+    @SYMTestActions    Get  glyph outline. Simulate OOM faliures using debug
+    macros to check if the program logic is correct.
+    @SYMTestExpectedResults    Open() always returns KErrNoMemory.
+*/
+void CTFontAndGlyph::GetGlyphWithNoMem()
+    {
+#ifdef _DEBUG 
+    __UHEAP_MARK;
+    RFbsSession *fbsSession = RFbsSession::GetSession();
+    
+    TUint glyphIndex[] = {4, 4, KInvalidGlyphId};  
+    __UHEAP_FAILNEXT(1);
+    RGlyphOutlineIterator it1;    
+    TInt err = it1.Open(*iFont, glyphIndex, sizeof(glyphIndex)/sizeof(glyphIndex[0]), ETrue);
+    TEST(err == KErrNoMemory);
+    it1.Close(); 
+    
+    __UHEAP_FAILNEXT(2);
+    RGlyphOutlineIterator it2;
+    err = it2.Open(*iFont, glyphIndex, sizeof(glyphIndex)/sizeof(glyphIndex[0]));
+    TEST(err == KErrNoMemory);
+    TEST(KErrNotFound == it2.Next());
+    it2.Close(); 
+    
+    __UHEAP_FAILNEXT(3);
+    RGlyphOutlineIterator it3;
+    err = it3.Open(*iFont, glyphIndex, sizeof(glyphIndex)/sizeof(glyphIndex[0]), ETrue);
+    TEST(err == KErrNoMemory);
+    TEST(KErrNotFound == it2.Next());
+    it3.Close(); 
+    
+    RGlyphOutlineIterator it4;  
+    fbsSession = RFbsSession::GetSession();
+    fbsSession->SendCommand(EFbsMessSetHeapFail, RFbsSession::EHeapFailTypeServerMemory, 1);
+    err = it4.Open(*iFont, glyphIndex, sizeof(glyphIndex)/sizeof(glyphIndex[0])); 
+    TEST(KErrNoMemory == err);
+    TEST(KErrNotFound == it2.Next());
+    fbsSession->SendCommand(EFbsMessSetHeapReset, RFbsSession::EHeapFailTypeServerMemory);
+    it4.Close();
+    
+    __UHEAP_FAILNEXT(4);
+    RGlyphOutlineIterator it5;
+    err = it5.Open(*iFont, glyphIndex, sizeof(glyphIndex)/sizeof(glyphIndex[0]));
+    TEST(err == KErrNoMemory);
+    TEST(KErrNotFound == it2.Next());
+    it5.Close();
+    __UHEAP_MARKEND;
+#else
+    INFO_PRINTF1(_L("Skipping test GetGlyphWithNoMem in release mode"));
+#endif
+    }
+
+
+/**
+    @SYMTestCaseID    TI18N-GDI-CIT-4079
+    @SYMTestCaseDesc    Get hinted glyph outline
+    @SYMTestActions    Get hinted glyph outline for glyph 4 and 65536. 
+    Pass NULL for the 'aCodes' argument, and 0 for the 'aCount' to test 
+    param validation. Check return values in each situation.
+    @SYMTestExpectedResults    Open() returns KErrNone. Outline() returns a 
+    valid pointer to the string representing the outline. OutlineLength() returns
+    the corresponding string length.
+*/
+void CTFontAndGlyph::GetHintedGlyphById()
+    {
+    __UHEAP_MARK;
+    RGlyphOutlineIterator glyphIterator1;
+    TUint glyphIndex[] = {4, 4, KInvalidGlyphId};  //two 4 to ensure the 2nd glyph is in cache.
+    TInt err = glyphIterator1.Open(*iFont, glyphIndex, sizeof(glyphIndex)/sizeof(glyphIndex[0]), ETrue);
+    TEST(err == KErrNone);  
+    TInt len1 = glyphIterator1.OutlineLength();   
+    const TUint8* ptr1 = glyphIterator1.Outline();
+    TInt end = glyphIterator1.Next();
+    const TUint8* ptr2 = glyphIterator1.Outline();
+    TInt len2= glyphIterator1.OutlineLength(); 
+    TEST(len1 > 0);  
+    TEST(ptr1 != NULL);
+    TEST(ptr1 == ptr2);  
+    TEST(len1 == len2); 
+        
+    RGlyphOutlineIterator glyphIterator1b;  // for font file 2
+    TUint glyphIndex_2[] = {0x41, 0x41, KInvalidGlyphId}; 
+    err = glyphIterator1b.Open(*iFont2, glyphIndex_2, 
+            sizeof(glyphIndex_2)/sizeof(glyphIndex_2[0]), ETrue);
+    TEST(err == KErrNone);  
+    len1 = glyphIterator1b.OutlineLength();   
+    ptr1 = glyphIterator1b.Outline();
+    end = glyphIterator1b.Next();
+    ptr2 = glyphIterator1b.Outline();
+    len2= glyphIterator1b.OutlineLength(); 
+    TEST(len1 > 0);  
+    TEST(ptr1 != NULL);
+    TEST(ptr1 == ptr2);  
+    TEST(len1 == len2); 
+    
+    end = glyphIterator1.Next();    
+    len1 = glyphIterator1.OutlineLength(); 
+    ptr1 = glyphIterator1.Outline();
+    // for the invalid glyph id, len1<0 indicates an error.
+    TEST(NULL == ptr1);
+    TEST(len1 < 0);
+    end = glyphIterator1.Next();
+    TEST(KErrNotFound == end);
+    // calling Outline() or OutlineLength() causes panic if Next() 
+    // returns KErrNotFound
+    glyphIterator1.Close();
+
+    end = glyphIterator1b.Next();    
+    len1 = glyphIterator1b.OutlineLength(); 
+    ptr1 = glyphIterator1b.Outline();
+    // for the invalid glyph id, len1<0 indicates an error.
+    TEST(NULL == ptr1);
+    TEST(len1 < 0);
+    end = glyphIterator1b.Next();
+    TEST(KErrNotFound == end);
+    // calling Outline() or OutlineLength() causes panic if Next() 
+    // returns KErrNotFound
+    glyphIterator1b.Close();
+    
+    RGlyphOutlineIterator glyphIterator3;
+    err = glyphIterator3.Open(*iFont, glyphIndex, 0, ETrue);
+    TEST(KErrArgument == err);
+    TEST(KErrNotFound == glyphIterator3.Next());
+    glyphIterator3.Close();  
+    
+    RGlyphOutlineIterator glyphIterator4;
+    err = glyphIterator4.Open(*iFont, NULL, sizeof(glyphIndex)/sizeof(glyphIndex[0]), ETrue);
+    TEST(KErrArgument == err);
+    TEST(KErrNotFound == glyphIterator4.Next());
+    glyphIterator4.Close(); 
+    __UHEAP_MARKEND;
+    }
+
+
+/**
+    @SYMTestCaseID    TI18N-GDI-CIT-4081
+    @SYMTestCaseDesc    Get hinted glyph outline, passing in invalid IDs.
+    @SYMTestActions    Get hinted glyph outline, passing in invalid IDs. Check 
+    the return values.
+    @SYMTestExpectedResults    Open() returns KErrNone. Outline() returns NULL.
+    OutlineLength() returns KErrGeneral.
+*/
+void CTFontAndGlyph::GetHintedGlyphByWrongId()
+    {
+    __UHEAP_MARK;
+    RGlyphOutlineIterator glyphIterator;
+    TUint glyphIndex[] = {KInvalidGlyphId, KInvalidGlyphId};  
+    TInt err = glyphIterator.Open(*iFont, glyphIndex, sizeof(glyphIndex)/sizeof(glyphIndex[0]), ETrue);
+    TEST(err == KErrNone);  
+    const TUint8* ptr = glyphIterator.Outline();
+    TInt len = glyphIterator.OutlineLength();
+    TEST(KErrGeneral == len);
+    TEST(ptr == NULL);
+    TInt ret = glyphIterator.Next();
+    TEST(KErrNone == ret);
+    glyphIterator.Close();
+    __UHEAP_MARKEND;
+    }
+
+
+/**
+    @SYMTestCaseID    TI18N-GDI-CIT-4080
+    @SYMTestCaseDesc    Get unhinted glyph outline
+    @SYMTestActions    Get unhinted glyph outline for glyph 4 and 5. 
+    @SYMTestExpectedResults    Open() returns KErrNone. Outline() and 
+    OutlineLength() returns the outline string and corresponding length.
+*/
+void CTFontAndGlyph::GetUnHintedGlyphById()
+    {
+    __UHEAP_MARK;
+    RGlyphOutlineIterator glyphIterator2;
+    TUint glyphIndex[] = {4, 4, 5};  //two '4' to ensure the 2nd is in cache.
+    TInt err = glyphIterator2.Open(*iFont, glyphIndex, sizeof(glyphIndex)/sizeof(glyphIndex[0]), EFalse);
+    TEST(err == KErrNone);   
+    const TUint8* ptr1 = glyphIterator2.Outline();
+    TInt len1 = glyphIterator2.OutlineLength();     
+    err = glyphIterator2.Next();
+    TEST(err == KErrNone);
+    const TUint8* ptr2 = glyphIterator2.Outline();
+    TInt len2= glyphIterator2.OutlineLength(); 
+    err = glyphIterator2.Next();
+    TEST(err == KErrNone);
+    TEST(len1 > 0);  
+    TEST(ptr1 == ptr2); 
+    TEST(ptr1 != NULL);
+    TEST(len1 == len2);      
+    
+    RGlyphOutlineIterator glyphIterator2b;  // for the 2nd font file
+    TUint glyphIndex2[] = {0x41, 0x41, 0x42}; 
+    err = glyphIterator2b.Open(*iFont2, glyphIndex2, 
+            sizeof(glyphIndex2)/sizeof(glyphIndex2[0]), EFalse);
+    TEST(err == KErrNone);   
+    ptr1 = glyphIterator2b.Outline();
+    len1 = glyphIterator2b.OutlineLength();     
+    err = glyphIterator2b.Next();
+    TEST(err == KErrNone);
+    ptr2 = glyphIterator2b.Outline();
+    len2= glyphIterator2b.OutlineLength(); 
+    err = glyphIterator2b.Next();
+    TEST(err == KErrNone);
+    TEST(len1 > 0);  
+    TEST(ptr1 == ptr2); 
+    TEST(ptr1 != NULL);
+    TEST(len1 == len2);
+    
+    glyphIterator2.Close();
+    glyphIterator2b.Close();
+    __UHEAP_MARKEND;
+    }
+
+/**
+    @SYMTestCaseID    TI18N-GDI-CIT-4087
+    @SYMTestCaseDesc    Pass invalid font handle to FBS when getting font table.
+    @SYMTestActions    Pass invalid font handle to FBS when getting font table.
+        And check the return value.
+    @SYMTestExpectedResults    Open returns KErrNotFound.
+*/
+void CTFontAndGlyph::TestFbsFontHandleIsZeroForFont() 
+    {
+    __UHEAP_MARK;
+    CFbsTestForFont* fbsFont = reinterpret_cast<CFbsTestForFont*> (iFont);
+    TEST(NULL != fbsFont);
+    fbsFont->SetHandle(0);
+    TInt handle = fbsFont->Handle();
+    CFbsTestForFont tempFsbFont;
+    tempFsbFont.Duplicate(handle);
+    tempFsbFont.SetHandle(0);    
+    RFontTable ft1;
+    TInt err = ft1.Open(tempFsbFont, 0x11667730);
+    TEST(err == KErrNotFound);
+    ft1.Close(); 
+    __UHEAP_MARKEND;
+    }
+
+/**
+    @SYMTestCaseID    TI18N-GDI-CIT-4088
+    @SYMTestCaseDesc    Pass invalid font handle to FBS when getting glyph outline.
+    @SYMTestActions    Pass invalid font handle to FBS when getting glyph outline.
+        And check the return value.
+    @SYMTestExpectedResults    Open() returns KErrNotFound.
+*/
+void CTFontAndGlyph::TestFbsFontHandleIsZeroForGlyph() 
+    {
+    __UHEAP_MARK;
+    CFbsTestForFont* fbsFont = reinterpret_cast<CFbsTestForFont*> (iFont);
+    TEST(NULL != fbsFont);
+    TInt handle = fbsFont->Handle();
+    CFbsTestForFont tempFsbFont;
+    tempFsbFont.Duplicate(handle);
+    tempFsbFont.SetHandle(0);     
+    RGlyphOutlineIterator glyphIterator1;
+    TUint glyphIndex[] = {1, 1, KInvalidGlyphId}; 
+    TInt err = glyphIterator1.Open(tempFsbFont, glyphIndex, sizeof(glyphIndex)/sizeof(glyphIndex[0]), ETrue);
+    TEST(err == KErrNotFound);
+    glyphIterator1.Close();    
+    __UHEAP_MARKEND;
+    }
+
+static TInt OutlinePanicThread(TAny* /* ptr */)
+    {   
+    CTrapCleanup* trapCleanup=CTrapCleanup::New();
+    RGlyphOutlineIterator it;
+    it.Outline();
+    delete trapCleanup;
+    return 0;
+    }
+
+static TInt OutlineLengthPanicThread(TAny* /* ptr */)
+    {   
+    CTrapCleanup* trapCleanup=CTrapCleanup::New();
+    RGlyphOutlineIterator it;
+    it.OutlineLength();
+    delete trapCleanup;
+    return 0;
+    }
+
+void CTFontAndGlyph::OutlinePanics(TInt (*aThreadFun)(TAny*))
+    {   
+    __UHEAP_MARK;
+    RThread thread;
+    TThreadFunction fun(aThreadFun);
+    TAny* ptr = NULL;
+    thread.Create(_L("RGlyphOutlineIterator"), fun, 0x1000, 0x20000, 0x20000, ptr);
+    
+    TRequestStatus status;
+    thread.Logon(status);
+    thread.Resume();
+    User::WaitForRequest(status);
+    
+    TInt err = thread.ExitReason();
+    TEST(err == 0);
+    TExitCategoryName name = thread.ExitCategory();
+    TEST(name == _L("GDI"));    
+    thread.Close();
+    __UHEAP_MARKEND;
+    }
+
+
+void CTFontAndGlyph::OutlineLengthPanics(TInt (*aThreadFun)(TAny*))
+    {   
+    __UHEAP_MARK;
+    RThread thread;
+    TThreadFunction fun(aThreadFun);
+    TAny* ptr = NULL;
+    thread.Create(_L("RGlyphOutlineLengthIterator"), fun, 0x1000, 0x20000, 0x20000, ptr);
+    
+    TRequestStatus status;
+    thread.Logon(status);
+    thread.Resume();  
+    User::WaitForRequest(status);
+    
+    TInt err = thread.ExitReason();
+    TEST(err == 0);
+    TExitCategoryName name = thread.ExitCategory();
+    TEST(name == _L("GDI"));
+    thread.Close();
+    __UHEAP_MARKEND;
+    }
+
+/**
+    @SYMTestCaseID    TI18N-GDI-CIT-4089
+    @SYMTestCaseDesc    Try to get glyph outline's length and content when 
+        the glyph is not found in font file.
+    @SYMTestActions    Try to get glyph outline's length and content when 
+        the glyph is not found in font file. This should cause a client panic.
+    @SYMTestExpectedResults    Both cases exit with ExitCategory 'GDI' and 
+    reason code 0.
+*/
+void CTFontAndGlyph::GlyphOutlineIteratorPanics()
+    {
+    __UHEAP_MARK;
+    OutlinePanics(OutlinePanicThread);
+    OutlineLengthPanics(OutlineLengthPanicThread);
+    __UHEAP_MARKEND;
+    }
+
+void CTFontAndGlyph::ConstructL()
+    {    
+    INFO_PRINTF1(_L("Calling CTFontAndGlyph::ConstructL()"));
+    iFontStore = CFontStore::NewL(&User::Heap());
+    LoadOpenFontLibraries(iFontStore);
+    iFontStore->iKPixelWidthInTwips = 11860;
+    iBmp = new (ELeave) CFbsBitmap;
+    User::LeaveIfError(iBmp->Create(TSize(100,100),EGray2));
+    iDevice = CFbsBitmapDevice::NewL(iBmp);
+    iUid = iFontStore->AddFileL(KTestFontFile);
+    TInt err = iDevice->GetNearestFontToMaxHeightInTwips(iFont,iFontSpec,0);
+    if (KErrNone != err)
+        {
+        iFontStore->RemoveFile(iUid);
+        User::Leave(err);
+        }   
+    
+    iBmp2 = new (ELeave) CFbsBitmap;  
+    User::LeaveIfError(iBmp2->Create(TSize(100,100),EGray2));
+    iDevice2 = CFbsBitmapDevice::NewL(iBmp2);
+    iUid2 = iFontStore->AddFileL(KTestFontFile2);
+    err = iDevice2->GetNearestFontToMaxHeightInTwips(iFont2,iFontSpec2,0);    
+    if (KErrNone != err)
+        {
+        iFontStore->RemoveFile(iUid);
+        iFontStore->RemoveFile(iUid2);
+        User::Leave(err);
+        }
+    }
+
+void CTFontAndGlyph::CleanEnv()
+    {
+    iDevice->ReleaseFont(iFont); 
+    delete iDevice;
+    delete iBmp;
+    iFontStore->RemoveFile(iUid);
+    
+    iDevice2->ReleaseFont(iFont2); 
+    delete iDevice2;
+    delete iBmp2;
+    iFontStore->RemoveFile(iUid2);
+    
+    delete iFontStore;
+    iDevice = NULL;
+    iBmp = NULL;
+    iFontStore = NULL;
+    
+    iDevice2 = NULL;
+    iBmp2 = NULL;
+    
+    REComSession::FinalClose();
+    }
+
+//--------------
+CTFontAndGlyphStep::CTFontAndGlyphStep()
+    {
+    SetTestStepName(KTFontTableAndGlyphStep);
+    }
+
+CTGraphicsBase* CTFontAndGlyphStep::CreateTestL()
+    {
+    return new (ELeave) CTFontAndGlyph(this);
+    }
+
+static void LoadOpenFontLibraries(CFontStore* aFontStore)
+    {
+
+    RImplInfoPtrArray implementationArray;
+    TInt error;
+    TInt ecomerror;
+    TInt ecomnotready;
+    TUid uid = {KUidOpenFontRasterizerPlunginInterface};
+
+    // Making sure that no race situation arises
+    // If ECom is not ready, give it another chance and try again. if it still doesn't work 
+    // after the third try, then it just carries on quietly and fails... 
+    for (ecomnotready =0; ecomnotready <3; ecomnotready++)
+        {
+        TRAP(ecomerror,REComSession::ListImplementationsL(uid,implementationArray));
+        if (!ecomerror)
+            {
+            break;
+            }
+        else
+            {
+            ecomerror = 0;  
+            User::After(0);
+            }
+        }
+
+    const TInt availCount = implementationArray.Count();
+    for (TInt count=0;count<availCount;++count)
+        {
+        const CImplementationInformation* info = implementationArray[count];
+        TUid rasterizerUid = info->ImplementationUid();
+        // Create a rasterizer
+        COpenFontRasterizer* rasterizer=0;
+        TRAP(error,rasterizer = COpenFontRasterizer::NewL(rasterizerUid));
+        if (!error)
+            {
+            // Install it in the font store.
+            TRAP(error,aFontStore->InstallRasterizerL(rasterizer));
+            if (error)
+                {
+                RDebug::Printf("tfonttableandglyph: failed to load rasterizer."); 
+                delete rasterizer;
+                }
+            }
+        }
+    
+    implementationArray.ResetAndDestroy();
+    }
+
+static TInt SMPAndWDPSafeTestFun(TAny* /*aParam*/)
+    {
+    CFbsBitmapDevice* device1 = NULL;
+    CFont* font;
+    TInt err = 0;
+    CTrapCleanup* trapCleanup=CTrapCleanup::New();
+    
+    err = RFbsSession::Connect();    
+    if(err != KErrNone)
+        User::Panic(_L("FbsSession connection error"), -1);    
+  
+    CFbsBitmap* bmp = NULL;
+    TRAPD(ret1, bmp = new (ELeave) CFbsBitmap);
+    if (bmp == NULL)
+        User::Panic(_L("new CFbsBitmap error"), -1);
+    err = bmp->Create(TSize(100,100),EGray2);
+    if(err != KErrNone)
+            User::Panic(_L("bitmap creation error"), -1);
+    TRAP(err,device1 = CFbsBitmapDevice::NewL(bmp));
+    if(err != KErrNone)
+        User::Panic(_L("fbs device new error"), -1);
+    TFontSpec fontSpec(KTestFontFaceName,KFontHeight); 
+    err = device1->GetNearestFontToMaxHeightInTwips(font,fontSpec,0);  
+    if(err != KErrNone)
+        User::Panic(_L("Get CFont error"), -1);
+    
+    err = KErrNone; 
+    for(TInt i = 0; i < 100; i++)
+    {
+    RFontTable fontTable;
+    err = fontTable.Open(*font, 0x68656164);
+    if (KErrNone != err)
+        {
+        User::Panic(_L("Font table opening failed with error"), err);
+        }
+    TUint32* ptr = (TUint32*)fontTable.TableContent();
+    if (ptr == NULL)
+        {
+        User::Panic(_L("Font table content NULL"), -1);
+        }
+    fontTable.Close();
+    }
+
+    delete device1;
+    delete bmp;
+    delete trapCleanup;
+    device1 = NULL;
+    bmp = NULL;
+    return err;
+    }
+
+/**
+    @SYMTestCaseID    TI18N-GDI-CIT-4090
+    @SYMTestCaseDesc    Test if the new code is SMP and WDP safe. 
+    @SYMTestActions    Create two threads to access the new interfaces concurrently.
+    @SYMTestExpectedResults    The threads run to the end correctly. All the
+    Open() operations succeed.
+*/
+void CTFontAndGlyph::SMPAndWDPSafeTest()
+    {
+    RThread thread1;
+    RThread thread2;
+    TThreadFunction fun(SMPAndWDPSafeTestFun);
+    
+    TInt ret1 = thread1.Create(_L("SMPAndWDPSafeThread1"), fun, 0x2000, 0x20000, 0x80000, iFontStore);
+	TEST(KErrNone == ret1);
+    TInt ret2 = thread2.Create(_L("SMPAndWDPSafeThread2"), fun, 0x2000, 0x20000, 0x80000, iFontStore);
+	TEST(KErrNone == ret2);
+    
+    TRequestStatus status1;
+    TRequestStatus status2;
+    thread1.Logon(status1);
+    thread2.Logon(status2);
+    thread1.Resume(); 
+    thread2.Resume(); 
+    User::WaitForRequest(status1);
+    User::WaitForRequest(status2);
+    
+    TEST(EExitKill == thread1.ExitType());
+    TEST(KErrNone == thread1.ExitReason());
+    TEST(EExitKill == thread2.ExitType());
+    TEST(KErrNone == thread2.ExitReason());
+    
+    thread1.Close();
+    thread2.Close();
+    }