fontservices/fontstore/src/OPENFONT.CPP
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 02:02:46 +0200
changeset 0 1fb32624e06b
child 1 e96e8a131979
permissions -rw-r--r--
Revision: 201003 Kit: 201005

/*
* Copyright (c) 2003-2009 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 <fntstore.h>
#include <gdi.h>
#include "FNTSTD.H"
#include <graphics/shapeimpl.h>
#include "ShaperCache.H"
#include "openfontsprivate.h"
#include <linkedfonts.h>
#include "linkedfontsprivate.h"
#include <graphics/openfontrasterizer.h>
#include <graphics/gdi/glyphsample.h>

const TInt KSessionCacheEntries = 512;
const TInt KDefaultSlantFactor = 20480;
const TInt KOneIn16Dot16FixedPointFormat = 65536;

#ifdef FNTSTORE_SUPPORT_FMM
class TPointerArrayBaseOffset
	{
public:
	TInt iCount;
	TAny** iEntries;
	TInt iAllocated;
	TInt iGranularity;
	};

/*RArrayGlyphEntries*/

inline const COpenFontGlyphTreeEntry& RArrayGlyphEntries::operator[](TInt anIndex) const
	{
	return *Entry(anIndex);
	}

inline COpenFontGlyphTreeEntry& RArrayGlyphEntries::operator[](TInt anIndex)
	{
	return *const_cast<COpenFontGlyphTreeEntry*>(Entry(anIndex));
	}

inline const COpenFontGlyphTreeEntry* RArrayGlyphEntries::Entry(TInt anIndex) const
	{
	return reinterpret_cast<const COpenFontGlyphTreeEntry*>(PtrAdd(EntryMemberOffSet()[anIndex],reinterpret_cast<TInt>(this)));
	}

inline COpenFontGlyphTreeEntry** RArrayGlyphEntries::EntryMemberOffSet() const
	{
	return reinterpret_cast<COpenFontGlyphTreeEntry**>(iEntriesOffset+reinterpret_cast<TInt>(this));
	}

inline TAny** RArrayGlyphEntries::EntryMember() const
	{
	return reinterpret_cast<const TPointerArrayBaseOffset*>(this)->iEntries;
	}

TInt RArrayGlyphEntries::Append(COpenFontGlyphTreeEntry& anEntry)
	{		
	TInt err = RArray<TInt>::Append(reinterpret_cast<TInt>(&anEntry)-reinterpret_cast<TInt>(this));
	if (err == KErrNone)
		{
		iEntriesOffset=reinterpret_cast<TInt>(EntryMember())-reinterpret_cast<TInt>(this);
		}
	return err;
	}
#endif // FNTSTORE_SUPPORT_FMM

/*COpenFontGlyphCache*/

TShapeHeader* COpenFontGlyphCache::SearchShaperCache(TInt aSessionHandle, TFontShapeFunctionParameters*& aParams)
	{
	if (iShaperCacheSentinel == NULL)
		return NULL;
	COpenFontShaperCacheEntry* searchNode = iShaperCacheSentinel->iNext;
	
	TInt start = aParams->iStart;
	TInt end = aParams->iEnd;
	TInt script = aParams->iScript;
	const TUint16* text = (TUint16*)aParams->iText->Ptr();
	TUint16* cachedText;
	const TUint16* copyOfText;
	TInt noOfChars = end - start;
	TInt textIsSame = 1;
	while (searchNode != iShaperCacheSentinel)
		{
		//Future work: add Script check for further script support
		//Future work: add Language check for further language support
		if ((searchNode->iEnd == end) && (searchNode->iStart == start) && (searchNode->iScript == script))
			{
			// Check for the entire text (within the context) coming in.
			TInt i = 0;
			copyOfText = text + start;
			cachedText = (TUint16*)searchNode->iText + searchNode->iStart;
			textIsSame = 1;
			while (i < noOfChars && textIsSame != 0)
				{
				if (*cachedText != *copyOfText)
					textIsSame = 0;
				i++;
				copyOfText++;
				cachedText++;
				};

			if (textIsSame)
				{
				if (searchNode == iShaperCacheSentinel->iNext)
					{
					// now we need to update the reference count here for that session
					if (searchNode->IncRefCount(aSessionHandle) != KErrNone)
						return NULL;
					return iShaperCacheSentinel->iNext->iShapeHeader;
					}
				// We have found a node, now put that node to the top of the list as the most recently used node
				searchNode->iPrevious->iNext = searchNode->iNext;
				searchNode->iNext->iPrevious = searchNode->iPrevious;
				
				searchNode->iNext = iShaperCacheSentinel->iNext;
				iShaperCacheSentinel->iNext->iPrevious = searchNode;
				iShaperCacheSentinel->iNext = searchNode;
				searchNode->iPrevious = iShaperCacheSentinel;
				if (searchNode->IncRefCount(aSessionHandle)!= KErrNone)
					return NULL;
				return searchNode->iShapeHeader;
				}
			}
			searchNode = searchNode->iNext;
		}
	return NULL;
	}

TShapeHeader* COpenFontGlyphCache::Insert(TInt aSessionHandle, RHeap* aHeap, CShaper::TInput aInput, TShapeHeader* aShapeHeader, TInt& aAddedBytes)
	{
	TInt heapSizeBefAloc = 0;
	aHeap->AllocSize(heapSizeBefAloc);

	COpenFontShaperCacheEntry* new_entry;
	new_entry = COpenFontShaperCacheEntry::New(aHeap, aInput, aShapeHeader);
	if (new_entry)
		{
		// increase the reference count for this
		TInt ret=new_entry->IncRefCount(aSessionHandle);
		if (ret != KErrNone)
			{
			//no memory here
			COpenFontShaperCacheEntry::Delete(aHeap, new_entry);
			return NULL;
			}
		new_entry->iNext = iShaperCacheSentinel->iNext;
		iShaperCacheSentinel->iNext->iPrevious = new_entry;
		iShaperCacheSentinel->iNext = new_entry;
		new_entry->iPrevious = iShaperCacheSentinel;

		iNumberOfShaperCacheEntries++;
		TInt heapSizeOnAloc = 0;
		aHeap->AllocSize(heapSizeOnAloc);
		aAddedBytes = heapSizeOnAloc - heapSizeBefAloc;

		// Update the amount of memory used in creation of a new entry
		iShapingInfoCacheMemory += heapSizeOnAloc - heapSizeBefAloc;

		return new_entry->iShapeHeader;
		}
	return NULL;
	}

/**
Searches from the least recently used towards the most recently used
and try to free entry that is no longer referenced
*/
TInt COpenFontGlyphCache::DeleteLeastRecentlyUsedEntry(RHeap* aHeap)
	{
	// start from the least recently used
	COpenFontShaperCacheEntry* deleteNode = iShaperCacheSentinel->iPrevious;

	// if empty list there is nothing to delete
	if (deleteNode == iShaperCacheSentinel)
		return 0;
	// else navigating starting from the LRU entry
	while (deleteNode != iShaperCacheSentinel)
		{
		// cannot delete if the iHandleRefCount is greater than zero
		if (deleteNode->iHandleRefCount>0)
			{
			deleteNode = deleteNode->iPrevious;
			continue;
			}

		// otherwise we can delete the entry
		deleteNode->iPrevious->iNext = deleteNode->iNext;
		deleteNode->iNext->iPrevious = deleteNode->iPrevious;

		TInt heapSizeBeforeDel = 0;
		TInt heapSizeAfterDel = 0;
		aHeap->AllocSize(heapSizeBeforeDel);
		COpenFontShaperCacheEntry::Delete(aHeap, deleteNode);
		aHeap->AllocSize(heapSizeAfterDel);
		TInt deletedBytes = heapSizeBeforeDel - heapSizeAfterDel;

		iNumberOfShaperCacheEntries--;
		iShapingInfoCacheMemory -= deletedBytes;

		return deletedBytes;
		}
	// we have navigated through the whole list and cannot delete anything
	return 0;
	}

TInt COpenFont::DecrementCachedRefCount(TInt aSessionHandle, TShapeHeader* aShapeHeader, TBool aResetAll)
	{
#ifdef FNTSTORE_SUPPORT_FMM
	COpenFontShaperCacheEntry* ptr=NULL;
	COpenFontGlyphCache* glyphCache=GetGlyphCache();
	if (glyphCache)
		ptr=glyphCache->iShaperCacheSentinel;
	if (!ptr)
		return KErrNone;
#else
	if (!iGlyphCache || !(iGlyphCache->iShaperCacheSentinel))
		return KErrNone;

	COpenFontShaperCacheEntry* ptr=iGlyphCache->iShaperCacheSentinel;
	COpenFontGlyphCache* glyphCache=iGlyphCache;
#endif // FNTSTORE_SUPPORT_FMM

	TInt ret = KErrNotFound;
	CFontStore* thisFontStore = File()->GetFontStore();
	TInt allocBefDec = 0;
	TInt allocAfterDec = 0;
	TInt deletedBytes = 0;

	// loop through the cache entry to decrement the ref count for a particular session	
	while (ptr->iNext)
		{
		if (aResetAll)
			{
			// we want to reset any cache that has a matching the session handle
			// i.e. here we dont care about which TShapeHeader and hence we can
			// ignore the error code here if not found

			// Always update the memory usage of the cache as decreasing the ref count 
			// releases memory
			iHeap->AllocSize(allocBefDec);

			ptr->DecRefCount(aSessionHandle, ETrue);

			iHeap->AllocSize(allocAfterDec);
			deletedBytes = allocBefDec - allocAfterDec;
			glyphCache->iShapingInfoCacheMemory -= deletedBytes;
			thisFontStore->SetShaperCacheMemUsage(thisFontStore->GetShaperCacheMemUsage() - deletedBytes);

			ret=KErrNone;
			}
		else if (ptr->iShapeHeader && ptr->iShapeHeader==aShapeHeader)
			{
			// Always update the memory usage of the cache as decreasing the ref count 
			// releases memory
			iHeap->AllocSize(allocBefDec);

			ptr->DecRefCount(aSessionHandle);

			iHeap->AllocSize(allocAfterDec);
			deletedBytes = allocBefDec - allocAfterDec;
			glyphCache->iShapingInfoCacheMemory -= deletedBytes;
			thisFontStore->SetShaperCacheMemUsage(thisFontStore->GetShaperCacheMemUsage() - deletedBytes);

			return KErrNone;
			}
		ptr=ptr->iNext;
		if (ptr == glyphCache->iShaperCacheSentinel)
			{
			break;
			}
		}
	return ret;
	}

TInt COpenFont::FreeShaperCacheMemory(TInt aBytesNeeded)
	{
	TInt totalDeletedBytes = 0;
	TInt tempDeletedBytes = 0;
	CFontStore* thisFontStore = File()->GetFontStore();

	if (aBytesNeeded <= KMaxShaperSesssionCacheMemory)
		{
		// delete LRU entries from all the caches except the one owned by this COpenFont
		// The 'if' condition here is to avoid looping through every font in the system
		// if only one of the them has a non-empty cache. In situations where only one
		// cache is left and it is full, this strategy makes freeing the memory faster.
		if (thisFontStore->GetNumShaperCaches() > 1)
			{
			CArrayPtrFlat<COpenFont>* fontList;
			CArrayPtrFlat<COpenFontFile>* fontFileList = thisFontStore->GetOpenFontFileList();
			TInt numberOfFontFiles = fontFileList->Count();
			TInt i = 0; 
			while ((totalDeletedBytes < aBytesNeeded) && (i < numberOfFontFiles))
				{
				fontList = (*fontFileList)[i]->GetOpenFontList();
				TInt fontListCount=fontList->Count();
				TInt j = 0;
				while ((totalDeletedBytes < aBytesNeeded) && (j < fontListCount))
					{
					COpenFont* open_font = (*fontList)[j];
					COpenFontGlyphCache* glyphCache = open_font->GetGlyphCache();
					if ((open_font != this) && (glyphCache != NULL))
						{
						while ((totalDeletedBytes < aBytesNeeded) && (!glyphCache->ShaperCacheIsEmpty()))
							{
							totalDeletedBytes += glyphCache->DeleteLeastRecentlyUsedEntry(iHeap);
							if (glyphCache->ShaperCacheIsEmpty())
								{
								thisFontStore->DecNumShaperCaches();
								}
								
							// If totalDeletedBytes is zero mean we cannot delete from this font
							if (totalDeletedBytes == 0)
								{
								break;
								}
							}
						}
					j++;
					}
				i++;
				}
			}
			
		// If deleted bytes are still less than the required one delete from this font
#ifdef FNTSTORE_SUPPORT_FMM
		COpenFontGlyphCache* glyphCache = GetGlyphCache();
#else
		COpenFontGlyphCache* glyphCache = iGlyphCache;
#endif // FNTSTORE_SUPPORT_FMM
		while (totalDeletedBytes < aBytesNeeded && !glyphCache->ShaperCacheIsEmpty())
			{				
			tempDeletedBytes = glyphCache->DeleteLeastRecentlyUsedEntry(iHeap);
			if ( tempDeletedBytes == 0)
				break;
			totalDeletedBytes += tempDeletedBytes;
			}
		}
		
	// Update the global CFontStore cache memory count
	if (totalDeletedBytes > 0)
		{
		thisFontStore->SetShaperCacheMemUsage(thisFontStore->GetShaperCacheMemUsage() - totalDeletedBytes);
		}

	return totalDeletedBytes;
	}

TShapeHeader* COpenFont::InsertShapedDataIntoCache(TInt aSessionHandle,TFontShapeFunctionParameters* aParams, TShapeHeader* aShapeHeader)
	{
	CShaper::TInput input;
	input.iEnd = aParams->iEnd;
	input.iStart = aParams->iStart;
	input.iScript = aParams->iScript;
	input.iLanguage = aParams->iLanguage;
	input.iText = aParams->iText;
	input.iMaximumAdvance = KMaxTInt;
	input.iFlags = 0;
	input.iSessionHandle = aSessionHandle;
	input.iReserved1 = 0;

	CFontStore* thisFontStore = File()->GetFontStore();

	// Create the glyph cache if it doesnt already exist.
	// This call can only come from FBSERV
	if (iGlyphCache == NULL)
		{
		iGlyphCache = (COpenFontGlyphCache*)iHeap->Alloc(sizeof(COpenFontGlyphCache));
		if (iGlyphCache == NULL) // no memory
			{
			return NULL;
			}
		new(iGlyphCache) COpenFontGlyphCache;
		}
	// If there is no sentinel present, i.e. new cache
	if (iGlyphCache->iShaperCacheSentinel == NULL)
		{
		// Create a sentinel
		iGlyphCache->iShaperCacheSentinel = COpenFontShaperCacheEntry::New(iHeap);
		if (!iGlyphCache->iShaperCacheSentinel)
			{
			// no memory
			return NULL;
			}
		iGlyphCache->iShaperCacheSentinel->iNext = iGlyphCache->iShaperCacheSentinel;
		iGlyphCache->iShaperCacheSentinel->iPrevious = iGlyphCache->iShaperCacheSentinel;
		iGlyphCache->iNumberOfShaperCacheEntries = 1;
		}

	// Before inserting into this cache, check if it was empty.
	// If empty, then increment the global cache count signifying one more cache is active
	if (iGlyphCache->ShaperCacheIsEmpty())
		{
		thisFontStore->IncNumShaperCaches();
		}

	TInt addedBytes = 0;
	TShapeHeader* cached_header = NULL;

	// Insert a new entry and return the newly inserted TShapeHeader entry
	cached_header = iGlyphCache->Insert(aSessionHandle, iHeap, input, aShapeHeader, addedBytes);
	if (cached_header == NULL)
		return NULL;

	// If the memory used by all the caches is greater than KMaxShaperSesssionCacheMemory, then
	// free some memory by releasing the same amount of memory that was just added
	if (thisFontStore->GetShaperCacheMemUsage() + addedBytes > KMaxShaperSesssionCacheMemory)
		{
		FreeShaperCacheMemory(addedBytes);
		}

	// Now update the memory count with the added memory for the new entry
	thisFontStore->SetShaperCacheMemUsage(thisFontStore->GetShaperCacheMemUsage() + addedBytes);
	return cached_header;
	}

TShapeHeader* COpenFont::GetShapedData(TInt aSessionHandle, TFontShapeFunctionParameters* aParams)
	{
	if (iGlyphCache == NULL)
		return NULL;

	TShapeHeader* cachedHeader = NULL;
	CFontStore* thisFontStore = File()->GetFontStore();

	// Always update the memory usage of the cache as increasing the reference count of a found header uses up memory
	TInt allocBefInc = 0;
	TInt allocAfterInc = 0;
	iHeap->AllocSize(allocBefInc);
	
#ifdef FNTSTORE_SUPPORT_FMM
	COpenFontGlyphCache* glyphCache = GetGlyphCache();
#else
	COpenFontGlyphCache* glyphCache = iGlyphCache;
#endif // FNTSTORE_SUPPORT_FMM
	cachedHeader = glyphCache->SearchShaperCache(aSessionHandle,aParams);
	
	iHeap->AllocSize(allocAfterInc);
	TInt addedBytes = allocAfterInc - allocBefInc;
	glyphCache->iShapingInfoCacheMemory += addedBytes;
	thisFontStore->SetShaperCacheMemUsage(thisFontStore->GetShaperCacheMemUsage() + addedBytes);

	return cachedHeader;
	}

TBool COpenFontGlyphCache::ShaperCacheIsEmpty()
	{
	if (iShaperCacheSentinel == NULL)
		return ETrue;

	if (iShaperCacheSentinel->iNext == iShaperCacheSentinel)
		return ETrue;
	else
		return EFalse;
	}

/**
C++ constructor taking shared heap, session cache list and font file as parameters.

You must either use this, or the other constructor, when creating your derived 
object. This constructor might be used, in preference to the other, if there 
is only a single typeface in the font file.

@param aHeap The shared heap. 
@param aSessionCacheList The session cache list.
@param aFile A pointer to the COpenFontFile object creating this COpenFont. 
e.g. when creating a COpenFont the COpenFontFile derived object would pass 
it this.
*/
#ifdef FNTSTORE_SUPPORT_FMM
EXPORT_C COpenFont::COpenFont(RHeap* aHeap,COpenFontSessionCacheList* aSessionCacheList,
							  COpenFontFile* aFile):
	iHeap(aHeap),
	iShaper(NULL),
	iFile(aFile),
	iFaceIndex(0),
	iSessionCacheList(aSessionCacheList)
	{	
	iStartingThis=reinterpret_cast<TInt>(this);
	}
#else
EXPORT_C COpenFont::COpenFont(RHeap* aHeap,COpenFontSessionCacheList* aSessionCacheList, COpenFontFile* aFile)
 :	iHeap(aHeap),
	iShaper(NULL),
	iFile(aFile),
	iFaceIndex(0),
	iSessionCacheList(aSessionCacheList),
	iReserved(NULL)
	{

	}
#endif // FNTSTORE_SUPPORT_FMM

/**
C++ constructor taking shared heap, session cache list, font file and face 
index as parameters.

You must either use this, or the other constructor, when creating your derived 
object. This constructor would be used if the font file contains more than 
one typeface.

@param aHeap The shared heap.
@param aSessionCacheList The session cache list.
@param aFile A pointer to the COpenFontFile object creating this COpenFont. 
e.g. when creating a COpenFont the COpenFontFile derived object would pass 
it this.
@param aFaceIndex The index of the typeface within the font file aFile.
*/
#ifdef FNTSTORE_SUPPORT_FMM
EXPORT_C COpenFont::COpenFont(RHeap* aHeap,COpenFontSessionCacheList* aSessionCacheList, COpenFontFile* aFile,TInt aFaceIndex) :
 	iHeap(aHeap),
	iShaper(NULL),
	iFile(aFile),
	iFaceIndex(aFaceIndex),
	iSessionCacheList(aSessionCacheList)
	{
	iStartingThis=reinterpret_cast<TInt>(this);
	}
#else
EXPORT_C COpenFont::COpenFont(RHeap* aHeap,COpenFontSessionCacheList* aSessionCacheList, COpenFontFile* aFile,TInt aFaceIndex)
 :	iHeap(aHeap),
	iShaper(NULL),
	iFile(aFile),
	iFaceIndex(aFaceIndex),
	iSessionCacheList(aSessionCacheList),
	iReserved(NULL)
	{

	}
#endif // FNTSTORE_SUPPORT_FMM

/**
Destructor

This function frees all memory owned by the object, including the session 
cache list and the glyph list, prior to its destruction.
*/
EXPORT_C COpenFont::~COpenFont()
	{
	//Delete the shaper
	delete iShaper;

	File()->GetFontStore()->CleanupCacheOnOpenFontRemoval(this);
	
	if (iGlyphCache)
		{
		COpenFontGlyphTreeEntry* next = NULL;
#ifdef FNTSTORE_SUPPORT_FMM
		TInt ii;
		RArrayGlyphEntries& glyphArray=iGlyphCache->iGlyphArray;
		for (ii=glyphArray.Count()-1;ii>=0;--ii)
			{
			next=&glyphArray[ii];
			COpenFontGlyph::Delete(iHeap,next);
			}
		iGlyphCache->iGlyphArray.Close();
#else
		for (COpenFontGlyphTreeEntry* g = iGlyphCache->iGlyphList; g; g = next)
			{
			next = g->iNext;
			COpenFontGlyph::Delete(iHeap, g);
			}
#endif // FNTSTORE_SUPPORT_FMM

		// Delete the shaper cache as well
		if (iGlyphCache->iShaperCacheSentinel)
			{
			COpenFontShaperCacheEntry* previous  = NULL;
			COpenFontShaperCacheEntry* si = iGlyphCache->iShaperCacheSentinel->iPrevious;
			TInt heapBefore = 0;
			TInt heapAfter = 0;
			iHeap->AllocSize(heapBefore);
			while (iGlyphCache->iNumberOfShaperCacheEntries > 0)
				{
				previous = si->iPrevious;
				COpenFontShaperCacheEntry::Delete(iHeap, si);
				si = previous;
				iGlyphCache->iNumberOfShaperCacheEntries--;
				}
			iHeap->AllocSize(heapAfter);
			File()->GetFontStore()->SetShaperCacheMemUsage(File()->GetFontStore()->GetShaperCacheMemUsage() - (heapBefore - heapAfter));
			File()->GetFontStore()->DecNumShaperCaches();
			}

		iHeap->Free(iGlyphCache);
		}
	if (iSessionCacheList)	
		iSessionCacheList->DeleteFontGlyphs(iHeap, this);
	if (iFile)
		iFile->RemoveFontFromList(this);
	}

COpenFontGlyph::~COpenFontGlyph()
	{
	}

void COpenFontGlyph::Delete(RHeap* aHeap, COpenFontGlyph* aGlyph)
	{
	if (aGlyph)
		{
#ifdef FNTSTORE_SUPPORT_FMM
		aHeap->Free(aGlyph->Bitmap());
#else
		aHeap->Free(aGlyph->iBitmap);
#endif // FNTSTORE_SUPPORT_FMM
		aHeap->Free(aGlyph);
		}
	}

EXPORT_C void COpenFont::operator delete(TAny *aFont)
	{
	if(aFont)
		{
		COpenFont* f = (COpenFont*)aFont;
		if (f->iHeap)
			f->iHeap->Free(aFont);
		}
	}

/**
Rasterize a glyph

This function may only be called via an FBSERV message.

@param aSessionHandle Session handle of the calling session
@param aCode Unicode value or glyph code if top bit is set
@param aGlyphData
	Output data. May be null, in which case output may be
	obtained through a call to GetCharacterData.

@return
	ETrue if aGlyphData contains valid data (that is, if aGlyphData->Bitmap()
	and aGlyphData->Metrics() are valid), EFalse otherwise.
*/
#ifdef FNTSTORE_SUPPORT_FMM
TBool COpenFont::Rasterize(TInt aSessionHandle, TInt aCode,
	TOpenFontGlyphData* aGlyphData)
	{
	// create the cache if it doesn't exisit. As this call can only come from
	// FBSERV if the chunk has to be resized then no panic will happen.
	if (iGlyphCache == NULL)
		{
		iGlyphCache = (COpenFontGlyphCache*)iHeap->Alloc(sizeof(COpenFontGlyphCache));
		if (iGlyphCache == NULL) // no memory
			{
			return EFalse;
			}
		new(iGlyphCache) COpenFontGlyphCache;
		}

	// Look in the Font Cache	
	TInt* nodeInsertPtr = NULL;	
	const COpenFontGlyph* g = FontCacheGlyph(aCode, nodeInsertPtr);		 	

	// If it is not found there look in the session cache.
	COpenFontSessionCache* cache = NULL;
	TInt index = 0;
	if (!g)
		{
		g = SessionCacheGlyph(iHeap, aSessionHandle, aCode, cache, index, EFalse);
		}

	// If it has already been rasterized return it.
	if (g)
		{
		if (aGlyphData)
			{
			aGlyphData->SetMetricsPointer(&g->iMetrics);
			aGlyphData->SetBitmapPointer(g->Bitmap());
			}

		return ETrue;
		}

	// Rasterize the glyph.
	TOpenFontGlyphData* temp_glyph_data = NULL;
	TInt error = KErrNone;
	TRAP(error, RasterizeHelperL(aCode, aGlyphData, temp_glyph_data));
	if (error != KErrNone)
		{
		iHeap->Free(temp_glyph_data);
		return EFalse;
		}

	TBool glyph_data_valid = ETrue;
	const TOpenFontGlyphData* cur_glyph_data = temp_glyph_data ? temp_glyph_data : aGlyphData;
	const COpenFontGlyph* new_glyph = NULL;

	// If the maximum per-font cache memory will not be exceeded, put the glyph into the font cache.
	TInt bytes = sizeof(COpenFontGlyphTreeEntry) + cur_glyph_data->BytesNeeded();	
	if(iGlyphCache && bytes + iGlyphCache->iGlyphCacheMemory <= KMaxGlyphCacheMemory)
		{
		COpenFontGlyphTreeEntry* new_entry = COpenFontGlyphTreeEntry::New(iHeap, aCode, cur_glyph_data->GlyphIndex(), *cur_glyph_data->Metrics(), cur_glyph_data->Bitmap());
		new_glyph=new_entry;
		if(new_entry)
			{
			// Insert new entry into the delete list 
			error = iGlyphCache->iGlyphArray.Append(*new_entry);
			if (error == KErrNone)
				{
				if(!iGlyphCache->iGlyphTreeOffset)
					{
					// First entry in tree
					iGlyphCache->iGlyphTreeOffset = PointerToThisOffset(new_entry);
					}	
				else if (nodeInsertPtr)
					{
					// Add the glyph to a leaf node using the nodeInsertPtr that was returned by FontCacheGlyph()
					*nodeInsertPtr = PointerToThisOffset(new_entry);
					}
				else 
					{
					// Failed to add the glyph to the glyph tree, remove it from the delete array.
					// (The glyph is deleted below).
					iGlyphCache->iGlyphArray.Remove(iGlyphCache->iGlyphArray.Count()-1);					
					error = KErrGeneral;
					}
				}
			if (error != KErrNone)
				{
				COpenFontGlyph::Delete(iHeap,new_entry);
				}
			else
				{
				iGlyphCache->iGlyphCacheMemory += bytes;
				}		
			}
		}
	else
		{
		error = KErrGeneral;
		}

	// Otherwise put the glyph into the per-session cache.
	if (error != KErrNone)
		{
		// If the session cache is not yet known find it or create one.
		if (!cache)
			{
			SessionCacheGlyph(iHeap, aSessionHandle, aCode, cache, index, TRUE);
			}
		if (!cache)
			{			
			return EFalse;
			}

		COpenFontSessionCacheEntry* new_entry =
			COpenFontSessionCacheEntry::New(iHeap, this, aCode, cur_glyph_data->GlyphIndex(), *cur_glyph_data->Metrics(), cur_glyph_data->Bitmap());
		new_glyph = new_entry;
		if (new_entry)
			{
			cache->Insert(iHeap, new_entry, index);
			}
		}

	if (temp_glyph_data)
		{
		iHeap->Free(temp_glyph_data);
        }
        
    // Fix up the returned glyph data pointers to point to the actual data.
    if (!new_glyph)
        glyph_data_valid = FALSE;
    else if (aGlyphData)
        {
        aGlyphData->SetMetricsPointer(&new_glyph->iMetrics);
        aGlyphData->SetBitmapPointer(new_glyph->Bitmap());
        }

	return glyph_data_valid;
	}
#else
TBool COpenFont::Rasterize(TInt aSessionHandle, TInt aCode,
	TOpenFontGlyphData* aGlyphData)
	{
	// First look in the font cache.
	COpenFontGlyphTreeEntry** node_ptr = NULL;
	// create the cache if it doesn't exisit. As this call can only come from
	// FBSERV if the chunk has to be resized then no panic will happen.
	if (iGlyphCache == NULL)
		{
		iGlyphCache = (COpenFontGlyphCache*)iHeap->Alloc(sizeof(COpenFontGlyphCache));
		if (iGlyphCache == NULL) // no memory
			{
			return FALSE;
			}
		new(iGlyphCache) COpenFontGlyphCache;
		}
	
	// Look in the fontcache. Do not expect to find a glyph here. However, 
	// it is called again so that a node pointer is found where the new glyph
	// will be placed when added to the font cache.
	const COpenFontGlyph* glyph = FontCacheGlyph(aCode, node_ptr);
	if (glyph)
		{
		// Do not expect it to get here, since the font cache has already been searched client-side,
		// prior to calling Rasterize(). However, just in case it does find a match, use it.
		if (aGlyphData)
			{
			aGlyphData->SetMetricsPointer(&glyph->iMetrics);
			aGlyphData->SetBitmapPointer(glyph->iBitmap);
			}
		return TRUE;
		}
		
	// Rasterize the glyph.
	TOpenFontGlyphData* temp_glyph_data = NULL;
	TInt error = KErrNone;
	TRAP(error, RasterizeHelperL(aCode, aGlyphData, temp_glyph_data));
	if (error)
		{
		iHeap->Free(temp_glyph_data);
		return FALSE;
		}

	TBool glyph_data_valid = TRUE;
	const TOpenFontGlyphData* cur_glyph_data = temp_glyph_data ? temp_glyph_data : aGlyphData;
	const COpenFontGlyph* new_glyph = NULL;

	// If the maximum per-font cache memory will not be exceeded, put the glyph into the font cache.
	TInt bytes = sizeof(COpenFontGlyphTreeEntry) + cur_glyph_data->BytesNeeded();
	if (iGlyphCache && node_ptr && bytes + iGlyphCache->iGlyphCacheMemory <= KMaxGlyphCacheMemory)
		{
		COpenFontGlyphTreeEntry* new_entry = COpenFontGlyphTreeEntry::New(iHeap, aCode, cur_glyph_data->GlyphIndex(), *cur_glyph_data->Metrics(), cur_glyph_data->Bitmap());
		new_glyph = new_entry;
		if (new_entry)
			{
			*node_ptr = new_entry;	// update the cache atomically

			// Insert new entry into the delete list 

			COpenFontGlyphTreeEntry* start = iGlyphCache->iGlyphTree;
			COpenFontGlyphTreeEntry* tree = start;

			if (new_entry != iGlyphCache->iGlyphTree)
				{
				while (tree->iNext)
					{
					tree = tree->iNext;
					}
				tree->iNext = new_entry;
				}
			else
				{
				// First entry in tree, initialise iGlyphList
				iGlyphCache->iGlyphList = new_entry;
				}

			iGlyphCache->iGlyphCacheMemory += bytes;
			}
		}

	// Otherwise put the glyph into the per-session cache.
	else
		{
		// If the session cache is not yet known find it or create one.
		COpenFontSessionCache* cache = NULL;
		TInt index = 0;
		SessionCacheGlyph(iHeap, aSessionHandle, aCode, cache, index, TRUE);
		if (!cache)
			return FALSE;
		COpenFontSessionCacheEntry* new_entry =
			COpenFontSessionCacheEntry::New(iHeap, this, aCode, cur_glyph_data->GlyphIndex(), *cur_glyph_data->Metrics(), cur_glyph_data->Bitmap());
		new_glyph = new_entry;
		if (new_entry)
			cache->Insert(iHeap, new_entry, index);
		}

	if (temp_glyph_data)
		{
            iHeap->Free(temp_glyph_data);
        }
        
    // Fix up the returned glyph data pointers to point to the actual data.
    if (!new_glyph)
        glyph_data_valid = FALSE;
    else if (aGlyphData)
        {
        aGlyphData->SetMetricsPointer(&new_glyph->iMetrics);
        aGlyphData->SetBitmapPointer(new_glyph->iBitmap);
        }

	return glyph_data_valid;
	}
#endif // FNTSTORE_SUPPORT_FMM

void COpenFont::RasterizeHelperL(TInt aCode, TOpenFontGlyphData* aGlyphData, TOpenFontGlyphData*& aTempGlyphData)
	{
	aTempGlyphData = 0;
	MOpenFontShapingExtension* extensionInterface = 0;

	// if the MSB is set this is a request to rasterize a glyph code
	// rather than a unicode value.  This can only be done if the rasterizer
	// supports the extended API. 
	if ( aCode & 0x80000000 )
		{
		aCode = GLYPH_CODE(aCode);
		// get the extension API for RasterizeGlyphL() if available
		TAny* ext = NULL;
		ExtendedInterface(KUidOpenFontShapingExtension, ext);
		extensionInterface = reinterpret_cast<MOpenFontShapingExtension*>(ext);

		if (!extensionInterface)
			// an attempt to rasterize a glyph when the rasterizer does not
			// support it; best to do nothing
			return;
		}
	TOpenFontGlyphData* currGlyphData = aGlyphData;

	if (!currGlyphData)
		{
		aTempGlyphData = TOpenFontGlyphData::New(iHeap, 0);
		if (!aTempGlyphData)
			User::Leave(KErrNoMemory);
		currGlyphData = aTempGlyphData;
		}

	if (extensionInterface)
		extensionInterface->RasterizeGlyphL(aCode, currGlyphData);
	else
		RasterizeL(aCode, currGlyphData);

	// If the GlyphData object was not large enough, create a temporary one
	// that can then be deleted by the caller.
	if (currGlyphData->Overflow())
		{
		TInt bytesNeeded = currGlyphData->BytesNeeded();
		if (aTempGlyphData)
			iHeap->Free(aTempGlyphData);
		aTempGlyphData = TOpenFontGlyphData::New(iHeap, bytesNeeded);
		if (!aTempGlyphData)
			User::Leave(KErrNoMemory);
		
		currGlyphData = aTempGlyphData;

		// If the extension interface was used above, then use again here
		if (extensionInterface)
			extensionInterface->RasterizeGlyphL(aCode, currGlyphData);
		else
			RasterizeL(aCode, currGlyphData);
		}
		
	if (currGlyphData->Metrics() == NULL) 
		{
		User::Leave(KErrArgument);
		}
	}

/** @internalComponent */
void COpenFont::SetShaper(CShaper* aShaper)
	{
	iShaper = aShaper;
	}
	
/** @internalComponent */
CShaper* COpenFont::GetShaper()
	{
	return iShaper;
	}

/** @internalComponent */
TBool COpenFont::HasShaper() const
	{
	return iShaper != NULL;
	}

void COpenFont::DeleteShaper() const
	{
	delete iShaper;
	}

TInt COpenFont::GetFontTable(TUint32 aTag, TAny*& aTableContent, TInt& aLength) 
    {
    // get the extension API for GetTrueTypeTable() if available
    TAny* ext = NULL;
    ExtendedInterface(KUidOpenFontTrueTypeExtension, ext);
    MOpenFontTrueTypeExtension* extensionInterface = 
        reinterpret_cast<MOpenFontTrueTypeExtension*>(ext);

    TInt ret = KErrNone;
    if (!extensionInterface)
        {
        ret = KErrNotSupported;
        }
    else 
        {
        TUint32 tag = aTag;
        TInt len = 0;
        aTableContent = extensionInterface->GetTrueTypeTable(ret, tag, &len);
        if (KErrNone == ret) 
            {
            aLength = len;
            }
        }
    return ret;
    }

TInt COpenFont::GetGlyphOutline(TUint aCode, 
        TBool aHinted, TAny*& aOutline, TInt &aLength) 
    {
    // get the extension API for GetTrueTypeTable() if available
    TAny* ext = NULL;
    ExtendedInterface(KUidOpenFontGlyphOutlineExtension, ext);
    MOpenFontGlyphOutlineExtension *extensionInterface = 
        reinterpret_cast<MOpenFontGlyphOutlineExtension*>(ext);

    TInt ret = KErrNone;
    if (!extensionInterface)
        {
        ret = KErrNotSupported;
        }
    else 
        {
        ret = extensionInterface->GetGlyphOutline(aCode, ETrue, 
                aHinted, aOutline, aLength);
        }
    return ret;
    }
#ifdef FNTSTORE_SUPPORT_FMM
/** Given the passed pointer aAny, return an offset from it to the "this" pointer
of this COpenFont object.
@param aAny A pointer to an object that exists on the shared heap, i.e. the same heap
that this CCOpenFont object was created on.
@return An offset relative to the "this" pointer for this object, this offset can
be converted back to a pointer using ThisOffsetToPointer().
@see ThisOffsetToPointer().
@internalComponent 
 */
TInt COpenFont::PointerToThisOffset(const TAny* aAny)
	{
	if (aAny)
		{
		return ((TInt)aAny - (TInt)this);
		}
	return 0;
	}

/** Given the passed passed offset aThisOffset, convert it to a pointer relative to
the "this" pointer for this object.
@param aThisOffset An offset that was generated using PointerToThisOffset().
@return A pointer that has been created by adding (this+aThisOffset).
@see PointerToThisOffset().
@internalComponent 
 */
TAny* COpenFont::ThisOffsetToPointer(const TInt aThisOffset)
	{
	if (aThisOffset)
		{
		return (TAny*)((TInt)this + aThisOffset);
		}
	return NULL;
	}		
#endif // FNTSTORE_SUPPORT_FMM

/**
A constructor initialised with a TCharacterMetrics object.

This is the old-style character metrics object. As for other T classes, there 
is no need to explicitly cleanup TOpenFontCharMetrics objects.

@param aMetrics The old-style metrics object.
*/
EXPORT_C TOpenFontCharMetrics::TOpenFontCharMetrics(const TCharacterMetrics& aMetrics)
	{
	iWidth = (TInt16)(aMetrics.iMoveInPixels - aMetrics.iLeftAdjustInPixels - aMetrics.iRightAdjustInPixels);
	iHeight = aMetrics.iHeightInPixels;
	iHorizBearingX = aMetrics.iLeftAdjustInPixels;
	iHorizBearingY = aMetrics.iAscentInPixels;
	iHorizAdvance = aMetrics.iMoveInPixels;
	iVertBearingX = 0;
	iVertBearingY = 0;
	iVertAdvance = aMetrics.iHeightInPixels;
	iGlyphBitmapType = 0;
	}

/**
Converts a TOpenFontCharacterMetrics object to a TCharacterMetrics.

@param aMetrics On return, contains the character's old-style metrics. 
@return ETrue if it was possible to get the metrics, otherwise EFalse.
*/
EXPORT_C TBool TOpenFontCharMetrics::GetTCharacterMetrics(TCharacterMetrics& aMetrics) const
	{
	aMetrics.iAscentInPixels = iHorizBearingY;
	aMetrics.iHeightInPixels = iHeight;
	aMetrics.iLeftAdjustInPixels = iHorizBearingX;
	aMetrics.iMoveInPixels = iHorizAdvance;
	aMetrics.iRightAdjustInPixels = (TInt16)(iHorizAdvance - iHorizBearingX - iWidth);
	return TRUE;
	}

TBool COpenFont::GetCharacterData(TInt aSessionHandle, TInt aCode, const TOpenFontCharMetrics*& aMetrics, const TUint8*& aBitmap) const
	{
	const COpenFontGlyph* g = Glyph(aSessionHandle, aCode);
	if (g)
		{
		aMetrics = &g->iMetrics;
#ifdef FNTSTORE_SUPPORT_FMM
		aBitmap = g->Bitmap();
#else
		aBitmap = g->iBitmap;
#endif // FNTSTORE_SUPPORT_FMM
		return TRUE;
		}
	else
		{
		aMetrics = NULL;
		aBitmap = NULL;
		return FALSE;
		}
	}



void COpenFont::OnFileDeleted()
	{
	iFile = NULL;
	}

COpenFontGlyphCache* COpenFont::GetGlyphCache()
	{
#ifdef FNTSTORE_SUPPORT_FMM
	if (iGlyphCache)
		return reinterpret_cast<COpenFontGlyphCache*>(reinterpret_cast<TInt>(iGlyphCache)+Offset());
#else
	if (iGlyphCache)
		return iGlyphCache;
#endif // FNTSTORE_SUPPORT_FMM
	else
		return NULL;
	}

const COpenFontGlyph* COpenFont::Glyph(TInt aSessionHandle, TInt aCode) const
	{	
#ifdef FNTSTORE_SUPPORT_FMM
	const COpenFontGlyph* glyph = const_cast<COpenFont*>(this)->FontCacheGlyph(aCode);
	if (!glyph)
		{			
		COpenFontSessionCache* cache;
		TInt index;
		glyph = SessionCacheGlyph(iHeap, aSessionHandle, aCode, cache, index, FALSE);
	}

	return glyph;
#else
	const COpenFontGlyph* g = CONST_CAST(COpenFont*,this)->FontCacheGlyph(aCode);
	if (!g)
		{
		COpenFontSessionCache* cache;
		TInt index;
		g = SessionCacheGlyph(iHeap, aSessionHandle, aCode, cache, index, FALSE);
		}
	return g;
#endif // FNTSTORE_SUPPORT_FMM
	}

/**
Is the specified character present in the font?
*/
TBool COpenFont::HasCharacterL(TInt aCode) const
	{
	COpenFontFile* file = File();
	if (file)
		return file->HasUnicodeCharacterL(iFaceIndex, aCode);
	else
		return FALSE;
	}

#ifdef FNTSTORE_SUPPORT_FMM
/**
Retrieve glyph data from the per-font glyph cache.
If it is not found return NULL. 
If the cache hasn't been created, then return NULL.
Previous versions of this function created the cache, but as this function can potentially
run in the context of threads other than FBSERV the alloc could panic if iHeap's chunk had to 
be resized - this is not allowed by the kernel.
The cache is now created in COpenFont::Rasterize which can only be called within the context of FBSERV
@param aCode The code for the glpyh to look for in the cache
@return A pointer to the requested glyph if it was found in the glyph cache, NULL if it was not found.
*/
const COpenFontGlyph* COpenFont::FontCacheGlyph(TInt aCode)
	{		
	if (COpenFontGlyphCache* glyphCache = GetGlyphCache())
		{		
		COpenFontGlyphTreeEntry* node = NULL;		
		if (glyphCache->iGlyphTreeOffset)
			{			
			node = static_cast<COpenFontGlyphTreeEntry*>(ThisOffsetToPointer(glyphCache->iGlyphTreeOffset));
			}
				
		while (node)
			{
			TInt code = node->iCode;
			if(code == aCode)
				{
				// Found the glyph
				return node;
				}		
			else if(code > aCode)
				{									
				node = static_cast<COpenFontGlyphTreeEntry*>(ThisOffsetToPointer(node->iLeftOffset));			
				}
			else
				{										
				node = static_cast<COpenFontGlyphTreeEntry*>(ThisOffsetToPointer(node->iRightOffset));			
				}
			}		
		}
	// No glyph found
	return NULL;
	}
	
/**
Retrieve glyph data from the per-font glyph cache.
If it is not found return NULL and place the address of the node pointer
to receive a new glyph in aNodeInsertPtr. 
If the cache hasn't been created, then return NULL.
Previous versions of this function created the cache, but as this function can potentially
run in the context of threads other than FBSERV the alloc could panic if iHeap's chunk had to 
be resized - this is not allowed by the kernel.
The cache is now created in COpenFont::Rasterize which can only be called within the context of FBSERV
@param aCode The code for the glpyh to look for in the cache
@param aNodeInsertPtr Returns a pointer to a final empty left or right leaf node
in the glpyh tree where the searched for glyph can be inserted if necessary.
@return A pointer to the requested glyph if it was found in the glyph cache, NULL if it was not found.
*/
const COpenFontGlyph* COpenFont::FontCacheGlyph(TInt aCode, TInt*& aNodeInsertPtr)
	{		
	aNodeInsertPtr = NULL;	

	if (COpenFontGlyphCache* glyphCache = GetGlyphCache())
		{		
		COpenFontGlyphTreeEntry* node = NULL;		
		if (glyphCache->iGlyphTreeOffset)
			{			
			node = static_cast<COpenFontGlyphTreeEntry*>(ThisOffsetToPointer(glyphCache->iGlyphTreeOffset));
			}
				
		while (node)
			{
			TInt code = node->iCode;
			if(code == aCode)
				{
				// Found the glyph
				return node;
				}		
			else if(code > aCode)
				{					
				aNodeInsertPtr = &node->iLeftOffset;
				node = static_cast<COpenFontGlyphTreeEntry*>(ThisOffsetToPointer(node->iLeftOffset));			
				}
			else
				{						
				aNodeInsertPtr = &node->iRightOffset;
				node = static_cast<COpenFontGlyphTreeEntry*>(ThisOffsetToPointer(node->iRightOffset));			
				}
			}		
		}

	// No glyph found
	return NULL;
	}
#else
/**
Retrieve glyph data from the per-font glyph cache.
If it is not found return NULL. 
If the cache hasn't been created, then return null.
Previous versions of this function created the cache, but as this function can potentially
run in the context of threads other than FBSERV the alloc could panic if iHeap's chunk had to 
be resized - this is not allowed by the kernel.
The cache is now created in COpenFont::Rasterize which can only be called within the context of FBSERV
*/
const COpenFontGlyph* COpenFont::FontCacheGlyph(TInt aCode)
	{
	if (iGlyphCache)
		{					
		COpenFontGlyphTreeEntry* node = iGlyphCache->iGlyphTree;
		while (node)
			{
			if (node->iCode == aCode)
				return node;
			if (node->iCode > aCode)
				node = node->iLeft;
			else
				node = node->iRight;
			}			
		}
	
	return NULL;
	}

/**
Retrieve glyph data from the per-font glyph cache.
If it is not found return NULL and place the address of the node pointer
to receive a new glyph in aNode. 
If the cache hasn't been created, then return null.
Previous versions of this function created the cache, but as this function can potentially
run in the context of threads other than FBSERV the alloc could panic if iHeap's chunk had to 
be resized - this is not allowed by the kernel.
The cache is now created in COpenFont::Rasterize which can only be called within the context of FBSERV
*/
const COpenFontGlyph* COpenFont::FontCacheGlyph(TInt aCode, COpenFontGlyphTreeEntry**& aNode)
	{
	if (!iGlyphCache)
		{
		aNode = NULL;
		return NULL;
		}

	aNode = &iGlyphCache->iGlyphTree;
	while (*aNode)
		{
		if ((*aNode)->iCode == aCode)
			return *aNode;
		if ((*aNode)->iCode > aCode)
			aNode = &((*aNode)->iLeft);
		else
			aNode = &((*aNode)->iRight);
		}
	
	return NULL;
	}
#endif // FNTSTORE_SUPPORT_FMM

/** Retrieve glyph data from the session cache. If the glyph is not in the
cache, return the cache and glyph index where the glyph data should be put. If
there is no session cache, optionally create it.

@param aHeap
	The heap on which to create the new cache, if appropriate. Not used if
	either the appropriate session cache already exists, or if aCreate is
	passed as false
@param aSessionHandle The session handle
@param aCode
	The code of the glyph to look up (Unicode or glyph code if the top bit is
	set)
@param aCache
	Returns the appropriate session cache, or NULL if an attempt to create it 
	has failed.
@param aIndex
	Returns where the glyph is, or should be put
@param aCreate
	If False, creation of a new cache is inhibited
@return The glyph data, or null if the glyph is not in the cache
@internalComponent
*/
#ifdef FNTSTORE_SUPPORT_FMM
const COpenFontGlyph* COpenFont::SessionCacheGlyph(RHeap* aHeap,
	TInt aSessionHandle, TInt aCode, COpenFontSessionCache*& aCache,
	TInt& aIndex, TBool aCreate) const
	{
	aIndex = 0;
	COpenFontSessionCacheListItem* prev = NULL;

	COpenFontSessionCacheList* cachelist = const_cast<COpenFont*>(this)->SessionCacheList();
	RSemaphore sem;
	if(KErrNone != sem.OpenGlobal(KSessionCacheSemaphoreName))
	    {
	    RDebug::Print(_L("COpenFont::SessionCacheGlyphe() can't open SessionCacheSemaphore"));
	    return NULL;
	    }
	sem.Wait();
	COpenFontSessionCacheListItem* cacheListStart=cachelist->Start();
	if(cacheListStart)
		{
		for (COpenFontSessionCacheListItem* p = cacheListStart; p; p = p->Next())
			{
			COpenFontSessionCache* cache=p->Cache();
			if (cache->iSessionHandle == aSessionHandle)
				{
				aCache = cache;
				sem.Signal();
				sem.Close();
				return aCache->Glyph(this,aCode,aIndex);
				}
			prev = p;
			}
		}
	sem.Signal();
	sem.Close();
	
	if (aCreate)
		{
		COpenFontSessionCache* new_cache = NULL;
		TRAPD(error, new_cache = COpenFontSessionCache::NewL(aHeap, aSessionHandle, KSessionCacheEntries));
		
		if ((!error) && new_cache)
			{
			COpenFontSessionCacheListItem* new_item = (COpenFontSessionCacheListItem*)aHeap->Alloc(sizeof(COpenFontSessionCacheListItem));
			if (!new_item)
				{
				new_cache->Delete(aHeap);	
				aHeap->Free(new_cache);
				return NULL;
				}

			new(new_item) COpenFontSessionCacheListItem(new_cache);

			if (prev)
				{
				prev->SetNext(new_item);
				}
			else
				{
				cachelist->SetStart(new_item);
				}

			aCache = new_cache;
			aIndex = GLYPH_CODE(aCode) % KSessionCacheEntries;
			}
		}
	return NULL;
	}
#else
const COpenFontGlyph* COpenFont::SessionCacheGlyph(RHeap* aHeap,
	TInt aSessionHandle, TInt aCode, COpenFontSessionCache*& aCache,
	TInt& aIndex, TBool aCreate) const
	{
	aCache = NULL;
	aIndex = 0;
	COpenFontSessionCacheListItem* prev = NULL;
    RSemaphore sem;
    if(KErrNone != sem.OpenGlobal(KSessionCacheSemaphoreName))
        {
        RDebug::Print(_L("COpenFont::SessionCacheGlyphe() can't open SessionCacheSemaphore"));
        return NULL;
        }
    sem.Wait();
	for (COpenFontSessionCacheListItem* p = iSessionCacheList->iStart; p; p = p->iNext)
		{
		if (p->iCache->iSessionHandle == aSessionHandle)
			{
			aCache = p->iCache;
		    sem.Signal();
		    sem.Close();
			return aCache->Glyph(this, aCode, aIndex);
			}
		prev = p;
		}
    sem.Signal();
	sem.Close();
	
	if (aCreate)
		{
		COpenFontSessionCache* new_cache = NULL;
		TRAPD(error, new_cache = COpenFontSessionCache::NewL(aHeap, aSessionHandle, KSessionCacheEntries));
		
		if ((!error) && new_cache)
			{
			COpenFontSessionCacheListItem* new_item = (COpenFontSessionCacheListItem*)aHeap->Alloc(sizeof(COpenFontSessionCacheListItem));
			if (!new_item)
				{
				new_cache->Delete(aHeap);	
				aHeap->Free(new_cache);
				return NULL;
				}

			new(new_item) COpenFontSessionCacheListItem(new_cache);

			if (prev)
				prev->iNext = new_item;
			else
				iSessionCacheList->iStart = new_item;

			aCache = new_cache;
			aIndex = GLYPH_CODE(aCode) % KSessionCacheEntries;
			}
		}
	return NULL;
	}
#endif // FNTSTORE_SUPPORT_FMM

/**
Create a glyph data object on the shared heap, given the code, metrics and the data bytes.
The data is copied; ownership remains with the caller.
*/
COpenFontGlyph* COpenFontGlyph::NewL(RHeap* aHeap, TInt aCode, TInt aGlyphIndex, const TOpenFontCharMetrics& aMetrics, const TDesC8& aBitmap)
	{
	COpenFontGlyph* glyph = (COpenFontGlyph*)aHeap->AllocL(sizeof(COpenFontGlyph));
	new(glyph) COpenFontGlyph(aCode, aGlyphIndex, aMetrics);
	if (!glyph->SetBitmap(aHeap, aBitmap))
		{
		aHeap->Free(glyph);
		User::Leave(KErrNoMemory);
		}
	return glyph;
	}	

COpenFontGlyphTreeEntry* COpenFontGlyphTreeEntry::New(RHeap* aHeap, TInt aCode, TInt aGlyphIndex, const TOpenFontCharMetrics& aMetrics, const TDesC8& aBitmap)
	{
	COpenFontGlyphTreeEntry* entry = (COpenFontGlyphTreeEntry*)aHeap->Alloc(sizeof(COpenFontGlyphTreeEntry));
	if (!entry)
		return NULL;
	new(entry) COpenFontGlyphTreeEntry(aCode, aGlyphIndex, aMetrics);
	if (!entry->SetBitmap(aHeap, aBitmap))
		{
		aHeap->Free(entry);
		entry = NULL;
		}
	return entry;
	}

COpenFontSessionCacheEntry* COpenFontSessionCacheEntry::New(RHeap* aHeap, const COpenFont* aFont, TInt aCode, TInt aGlyphIndex, const TOpenFontCharMetrics& aMetrics, const TDesC8& aBitmap) 
	{
	COpenFontSessionCacheEntry* entry = (COpenFontSessionCacheEntry*)aHeap->Alloc(sizeof(COpenFontSessionCacheEntry));
	if (!entry)
		return NULL;
	new(entry) COpenFontSessionCacheEntry(aFont, aCode, aGlyphIndex, aMetrics);
	if (!entry->SetBitmap(aHeap, aBitmap))
		{
		aHeap->Free(entry);
		entry = NULL;
		}
	return entry;
	}

#ifdef FNTSTORE_SUPPORT_FMM

inline COpenFont* COpenFontSessionCacheEntry::Font()const
{
if(iFontOffset)
    {
    return reinterpret_cast<COpenFont*>(reinterpret_cast<TInt>(this) + iFontOffset);
    }
else
    return NULL;
}

/**
@return A pointer to the run-length-encoded bitmap stored with this glyph, or NULL
if no bitmap has been stored with this glyph.
 */
TUint8* COpenFontGlyph::Bitmap() const
	{
	if (iBitmapOffset)
		{
		return (TUint8*)((TInt)this + iBitmapOffset);
		}
	return NULL;
	}
#endif // FNTSTORE_SUPPORT_FMM

TBool COpenFontGlyph::SetBitmap(RHeap* aHeap, const TDesC8& aBitmap)
	{
	TUint8* bitmap = (TUint8*)aHeap->Alloc(aBitmap.Length());
	if (!bitmap)
		return FALSE;
	Mem::Copy(bitmap, aBitmap.Ptr(), aBitmap.Length());	
#ifdef FNTSTORE_SUPPORT_FMM
	aHeap->Free(Bitmap());
	iBitmapOffset = (TInt)bitmap - (TInt)this;
#else
	if (iBitmap)
		aHeap->Free(iBitmap);
	iBitmap = bitmap;
#endif // FNTSTORE_SUPPORT_FMM
	return TRUE;
	}
#ifdef FNTSTORE_SUPPORT_FMM
COpenFontSessionCache* COpenFontSessionCache::NewL(RHeap* aHeap, TInt aSessionHandle, TInt aEntries)
	{
	COpenFontSessionCache* c = reinterpret_cast<COpenFontSessionCache*>(aHeap->AllocL(sizeof(COpenFontSessionCache)));
	new(c) COpenFontSessionCache(aSessionHandle,aEntries);
	TInt bytes = sizeof(TInt) * aEntries;
	TInt* entry= reinterpret_cast<TInt*>(aHeap->Alloc(bytes));
	Mem::FillZ(entry, bytes);
	if (!entry)
		{
		aHeap->Free(c);
		User::Leave(KErrNoMemory);
		}
	c->iEntryOffset = reinterpret_cast<TInt>(entry) - reinterpret_cast<TInt>(c);
	return c;
	}
#else
COpenFontSessionCache* COpenFontSessionCache::NewL(RHeap* aHeap, TInt aSessionHandle, TInt aEntries)
    {
    COpenFontSessionCache* c = (COpenFontSessionCache*)aHeap->AllocL(sizeof(COpenFontSessionCache));
    new(c) COpenFontSessionCache(aSessionHandle,aEntries);
    TInt bytes = sizeof(COpenFontSessionCacheEntry*) * aEntries;
    c->iEntry = (COpenFontSessionCacheEntry**)aHeap->Alloc(bytes);
    Mem::FillZ(c->iEntry, bytes);
    if (!c->iEntry)
        {
        aHeap->Free(c);
        User::Leave(KErrNoMemory);
        }
    return c;
    }
#endif //FNTSTORE_SUPPORT_FMM

#ifdef FNTSTORE_SUPPORT_FMM
void COpenFontSessionCache::Delete(RHeap* aHeap)
    {
    TInt* e =Entry();
    if(e)
        {
        for (TInt i = 0; i < iEntries; i++, e++)
            {
            if (ToCOpenFontSessionCacheEntryPointer(*e))
                {
                COpenFont* font=const_cast<COpenFont*>((ToCOpenFontSessionCacheEntryPointer(*e))->Font());
                if (font)
                    font->DecrementCachedRefCount(iSessionHandle, NULL, ETrue);
                aHeap->Free((ToCOpenFontSessionCacheEntryPointer(*e))->Bitmap());
                aHeap->Free(ToCOpenFontSessionCacheEntryPointer(*e));
                }
            }
        aHeap->Free(Entry());
        iEntryOffset = 0;
        }
    }
#else
void COpenFontSessionCache::Delete(RHeap* aHeap)
	{
	COpenFontSessionCacheEntry** e =iEntry;
	for (TInt i = 0; i < iEntries; i++, e++)
		{
		if (*e)
			{
			COpenFont* font=const_cast<COpenFont*>((*e)->iFont);
			if (font)
				font->DecrementCachedRefCount(iSessionHandle, NULL, ETrue);
			aHeap->Free((*e)->iBitmap);
			aHeap->Free(*e);
			}
		}
	aHeap->Free(iEntry);
	}
#endif //FNTSTORE_SUPPORT_FMM

const COpenFontGlyph* COpenFontSessionCache::Glyph(const COpenFont* aFont, TInt aCode, TInt& aIndex)
	{
	aIndex = -1;
	TInt oldest = KMaxTInt;
	TInt oldest_index = 0;
	TInt index = GLYPH_CODE(aCode) % iEntries;	// simple hash function to shorten searches
	for (TInt i = 0; i < iEntries; i++, index++)
		{
		if (index >= iEntries)
			index = 0;		
#ifdef FNTSTORE_SUPPORT_FMM
		COpenFontSessionCacheEntry* e = ToCOpenFontSessionCacheEntryPointer(Entry()[index]);
#else
		COpenFontSessionCacheEntry* e = iEntry[index];
#endif		//FNTSTORE_SUPPORT_FMM		
		if (!e)
			{
			if (aIndex == -1)
				aIndex = index;
			}
		else
			{
#ifdef FNTSTORE_SUPPORT_FMM
			if (e->Font() == aFont && e->iCode == aCode)
#else
			if (e->iFont == aFont && e->iCode == aCode)    
#endif //FNTSTORE_SUPPORT_FMM			    
				{
				e->iLastAccess = iLastAccess++;
				return e;
				}
			if (e->iLastAccess < oldest)
				{
				oldest = e->iLastAccess;
				oldest_index = index;
				}
			}
		}
	if (aIndex == -1)
		aIndex = oldest_index;
	return NULL;
	}


void COpenFontSessionCache::Insert(RHeap* aHeap, COpenFontSessionCacheEntry* aEntry, TInt aIndex)
	{
	if ((aIndex < 0) || (aIndex > iEntries))
		Panic(EFntSessionCacheIndexOutOfRange);
#ifdef 	FNTSTORE_SUPPORT_FMM
	COpenFontSessionCacheEntry* e = ToCOpenFontSessionCacheEntryPointer(Entry()[aIndex]);
	COpenFontGlyph::Delete(aHeap, e);
	Entry()[aIndex] = reinterpret_cast<TInt>(aEntry) - reinterpret_cast<TInt>(this);
#else
	COpenFontGlyph::Delete(aHeap, iEntry[aIndex]);
	iEntry[aIndex] = aEntry;
#endif  //FNTSTORE_SUPPORT_FMM	
	aEntry->iLastAccess = iLastAccess++;
	}

COpenFontSessionCache::COpenFontSessionCache(TInt aSessionHandle, TInt aEntries)
 :	iSessionHandle(aSessionHandle),  
	iEntries(aEntries),
	iLastAccess(0),
#ifdef  FNTSTORE_SUPPORT_FMM
    iEntryOffset(0)
#else 
    iEntry(NULL)
#endif  //FNTSTORE_SUPPORT_FMM  
	{
	}

#ifdef FNTSTORE_SUPPORT_FMM

inline TInt* COpenFontSessionCache::Entry() const
    {
    if (iEntryOffset)
        {
        return reinterpret_cast<TInt*>(reinterpret_cast<TInt>(this) + iEntryOffset);
        }
    return NULL;
    }

inline COpenFontSessionCacheEntry* COpenFontSessionCache::ToCOpenFontSessionCacheEntryPointer(TInt aOffset)const
    {
    if(aOffset)
        {
        return reinterpret_cast<COpenFontSessionCacheEntry*>(reinterpret_cast<TInt>(this) + aOffset);
        }
    return NULL;
    }

#endif // FNTSTORE_SUPPORT_FMM

/*COpenFontSessionCacheListItem*/
#ifdef FNTSTORE_SUPPORT_FMM
COpenFontSessionCacheListItem::COpenFontSessionCacheListItem(COpenFontSessionCache* aCache):
	iNextOffset(NULL)
	{
	if(aCache)
		{
		iCacheOffset = (TInt)aCache - (TInt)this;
		}
	else
		{
		iCacheOffset = NULL;
		}
	}

COpenFontSessionCacheListItem::~COpenFontSessionCacheListItem()
	{
	}
#endif // FNTSTORE_SUPPORT_FMM

/** Delete a COpenFontSessionCacheListItem from the passed heap.

@param aHeap The heap to delete the COpenFontSessionCacheListItem from.
 */
void COpenFontSessionCacheListItem::Delete(RHeap* aHeap)
	{
#ifdef FNTSTORE_SUPPORT_FMM
	Cache()->Delete(aHeap);	
	aHeap->Free(Cache());
	iCacheOffset=NULL;
	iNextOffset=NULL;
#else
	iCache->Delete(aHeap);	
	aHeap->Free(iCache);
	iCache=NULL;
#endif // FNTSTORE_SUPPORT_FMM
	}	

#ifdef FNTSTORE_SUPPORT_FMM
/** Get the next item to this cache list item.

@return A pointer to the next item to this one in the session cache, or NULL
if there is no next item.
 */
COpenFontSessionCacheListItem* COpenFontSessionCacheListItem::Next()
	{
	if(iNextOffset)
		{
		COpenFontSessionCacheListItem* next = (COpenFontSessionCacheListItem*)((TInt)this + (TInt)iNextOffset);
		return next;
		}
	else
		{
		return NULL;
		}
	}

/** Sets the next item to this in the session cache.

@param aNext Set this cache list item as the next item to this one in the session cache list.
 */
void COpenFontSessionCacheListItem::SetNext(COpenFontSessionCacheListItem* aNext)
	{
	if(aNext)
		{
		iNextOffset = (TInt)aNext - (TInt)this;
		}
	else
		{
		iNextOffset = NULL;
		}
	}

/** Get a pointer to the session cache that this cache list item is in.

@return A pointer to the session cache that this cache list item is part of.
 */
COpenFontSessionCache* COpenFontSessionCacheListItem::Cache()
	{
	if(iCacheOffset)
		{
		COpenFontSessionCache* cache = (COpenFontSessionCache*)((TInt)this + (TInt)iCacheOffset);
		return cache;
		}
	else
		{
		return NULL;
		}
	}

/** Get a pointer to the first item in the session cache.

@return A pointer to the first item in the session cache.
 */
COpenFontSessionCacheListItem* COpenFontSessionCacheList::Start()
	{
	if(iStartOffset)
		{
		COpenFontSessionCacheListItem* start = (COpenFontSessionCacheListItem*)((TInt)this + (TInt)iStartOffset);
		return start;
		}
	else
		{
		return NULL;
		}

	}

/** Set the passed item as the first item in the session cache. 

@param aItem An item to be added to the session cache
 */
void COpenFontSessionCacheList::SetStart(COpenFontSessionCacheListItem* aItem)
	{
	if(aItem!=NULL)
		{
		iStartOffset = (TInt)aItem - (TInt)this;
		}
	else
		{
		iStartOffset = 0;
		}
	}
#endif // FNTSTORE_SUPPORT_FMM

/** Delete all the items in the session cache if the current cache session handle
matches the passed session handle.

@param aHeap The heap base of the current process.
@param aSessionHandle The session handle of the cache to be deleted.
 */
void COpenFontSessionCacheList::DeleteCache(RHeap* aHeap, TInt aSessionHandle)
	{
	COpenFontSessionCacheListItem* prev = NULL;
	   RSemaphore sem;
	    if(KErrNone != sem.OpenGlobal(KSessionCacheSemaphoreName))
	        {
	        RDebug::Print(_L("COpenFontSessionCacheList::DeleteCache() can't open SessionCacheSemaphore"));
	        return;
	        }	    
#ifdef FNTSTORE_SUPPORT_FMM
 	for (COpenFontSessionCacheListItem* curr = Start(); curr; prev = curr, curr = curr->Next())
		{
 		if (curr->Cache()->iSessionHandle == aSessionHandle)
   			{
   			for(TInt i=0; i<KSessionCacheSemaphoreCount; i++)
   			    {
				//coverity[lock]
				//coverity[double_lock]
   			    sem.Wait();
   			    }
 			if (curr==Start())
 				SetStart(curr->Next());
 			else
 				prev->SetNext(curr->Next());
 				
   			curr->Delete(aHeap);
 			aHeap->Free(curr);
 			sem.Signal(KSessionCacheSemaphoreCount);
 			sem.Close();
   			return;
   			}
		}
#else
	for (COpenFontSessionCacheListItem* curr = iStart; curr; prev = curr, curr = curr->iNext)
		{
		if (curr->iCache->iSessionHandle == aSessionHandle)
			{
            for(TInt i=0; i<KSessionCacheSemaphoreCount; i++)
               {
               sem.Wait();
               }
			if (curr==iStart)
				iStart   = curr->iNext;
			else
				prev->iNext = curr->iNext;

			curr->Delete(aHeap);
			aHeap->Free(curr);
            sem.Signal(KSessionCacheSemaphoreCount);
            sem.Close();
			return;
			}
		}
#endif // FNTSTORE_SUPPORT_FMM
	}

/** Delete all the items in the current session cache.

@param aHeap The heap base of the current process.
 */
void COpenFontSessionCacheList::Delete(RHeap* aHeap)
	{
    RSemaphore sem;
    if(KErrNone != sem.OpenGlobal(KSessionCacheSemaphoreName))
        {
        RDebug::Print(_L("COpenFontSessionCacheList::Delete() can't open SessionCacheSemaphore"));
        return;
        }		
#ifdef FNTSTORE_SUPPORT_FMM
	COpenFontSessionCacheListItem* cur = Start();
#else
	COpenFontSessionCacheListItem* cur = iStart;
#endif // FNTSTORE_SUPPORT_FMM
	COpenFontSessionCacheListItem* next = NULL;

    for(TInt i=0; i<KSessionCacheSemaphoreCount; i++)
     {
	//coverity[lock]
	//coverity[double_lock]
     sem.Wait();     
     }
	while (cur)
		{
#ifdef FNTSTORE_SUPPORT_FMM
		next = cur->Next();
#else
		next = cur->iNext;
#endif // FNTSTORE_SUPPORT_FMM
		cur->Delete(aHeap);
		aHeap->Free(cur);
		cur = next;
		}
    sem.Signal(KSessionCacheSemaphoreCount);
    sem.Close();
	}

/**
Delete all glyphs belonging to a particular font.
*/
void COpenFontSessionCacheList::DeleteFontGlyphs(RHeap* aHeap, const COpenFont* aFont)
	{
    RSemaphore sem;
    if(KErrNone != sem.OpenGlobal(KSessionCacheSemaphoreName))
        {
        RDebug::Print(_L("COpenFontSessionCacheList::DeleteFontGlyphs can't global open SessionCacheSemaphore"));
        return;
        }
    sem.Wait();     
#ifdef FNTSTORE_SUPPORT_FMM     
	for (COpenFontSessionCacheListItem* p = Start(); p; p = p->Next())
		{
		COpenFontSessionCache* cache=p->Cache();
		TInt* e = cache->Entry();
		TInt entries = cache->iEntries;
		for (TInt i = 0; i < entries; i++, e++)
			{
			if ((cache->ToCOpenFontSessionCacheEntryPointer(*e)) 
			        && ((cache->ToCOpenFontSessionCacheEntryPointer(*e))->Font() == aFont))
				{
				COpenFontSessionCacheEntry::Delete(aHeap, cache->ToCOpenFontSessionCacheEntryPointer(*e));
				*e = 0;
				}
			}
		}
#else
	for (COpenFontSessionCacheListItem* p = iStart; p; p = p->iNext)
		{
		COpenFontSessionCacheEntry** e = p->iCache->iEntry;
		TInt entries = p->iCache->iEntries;
		for (TInt i = 0; i < entries; i++, e++)
			{
			if ((*e) && ((*e)->iFont == aFont))
				{
				COpenFontSessionCacheEntry::Delete(aHeap, *e);
				*e = NULL;
				}
			}
		}
#endif // FNTSTORE_SUPPORT_FMM
	
	sem.Signal();
	sem.Close();
	}

/**
C++ constructor with a CFont parameter.

This creates a TOpenFontMetrics and initialises it with size, ascent, maximum 
height, descent, maximum depth and maximum character width information from 
the CFont that was passed as a parameter.

@param aFont The font from which to initialise the metrics object.
*/
EXPORT_C TOpenFontMetrics::TOpenFontMetrics(const CFont* aFont)
	{
	iDesignHeight = (TInt16) aFont->HeightInPixels();
	iAscent = iMaxHeight = (TInt16) aFont->AscentInPixels();
	iDescent = iMaxDepth = (TInt16)(iDesignHeight - iAscent);
	iMaxWidth = (TInt16)aFont->MaxCharWidthInPixels();
	iBaselineCorrection = 0;
	}

/** 
@publishedPartner
@prototype

@param aBaselineCorrection The baseline correction to be associated with this font

Sets the baseline correction applied to this font; this value is used to offset
the underlinke and strikethrough positions and is used by linked fonts only.
*/
const TUint16 KBitsForUnderline = 10;
const TUint16 KMaskUnderline = (1<<KBitsForUnderline)-1;  //bottom bits which are set 
const TUint16 KMaskBitmapType = ~KMaskUnderline;  //top bits which are set
const TUint16 KSignBit = 1<<(KBitsForUnderline-1); //sign bit for the lower number, which can be signed
const TUint32 KTop16Of32Bits = 0xffff0000; 

EXPORT_C void TOpenFontMetrics::SetBaselineCorrection(TInt aBaselineCorrection)
	{
	__ASSERT_DEBUG(aBaselineCorrection<(1<<(KBitsForUnderline-1)), Panic(EFntOverFlow));
	__ASSERT_DEBUG(aBaselineCorrection>(0-(1<<(KBitsForUnderline-1))), Panic(EFntOverFlow));
	
	TUint16 value = iBaselineCorrection;
	value &=~KMaskUnderline; //zero all the underline position bits
	if (aBaselineCorrection<0)
		{
		//need to mask out extra sign bits for negative value
		iBaselineCorrection = value | (static_cast<TUint16>(aBaselineCorrection)&~KMaskBitmapType);
		}
	else
		{
		iBaselineCorrection = value | static_cast<TUint16>(aBaselineCorrection);
		}
	}

/**
@publishedPartner
@prototype

Gets the baseline correction applied to this font; this value is used to offset
the underlinke and strikethrough positions and is used by linked fonts only.

@return The baseline correction associated with this font
*/

EXPORT_C TInt TOpenFontMetrics::BaselineCorrection()
	{
	TUint16 value = iBaselineCorrection;  //read once for improved multi threading
	if (!(value & KSignBit))
		{
		//value is positive, no need to sign extend
		return value & KMaskUnderline;
		}
	else
		{
		//value is negative, need to stuff ones into the high bits
		//could shift up and shift down
		return static_cast<TInt>(static_cast<TUint>(value) | KMaskBitmapType | KTop16Of32Bits);
		}
	}

/**
C++ constructor with UID and filename.

Call this constructor in the constructor for your derived object, passing 
it aUid and aFileName arguments.

Non Symbian-platform-native font files are allocated IDs by the font store. 
These are passed in by the rasteriser class. UIDs are required by the 
font framework. However you should not use the ID to access the file, since 
a new UID will need to be allocated when the file is next loaded, e.g. after 
a device reboot. Instead use the font file name.

@param aUid The UID of the font file.
@param aFileName The full filename, including the path, of the font file.
*/
EXPORT_C COpenFontFile::COpenFontFile(TInt aUid, const TDesC& aFileName)
 :	iFaceAttrib(1),
	iUid(TUid::Uid(aUid)),
	iFileName(aFileName),
	iFontList(8)
	{
	}

/**
Destructor.

It is not allowed that file is deleted before its fonts
and the logic is handled in CFontStore::RemoveFile().
*/
EXPORT_C COpenFontFile::~COpenFontFile()
	{
    CFontStore *fs = GetFontStore();
    if (fs)
        {
        fs->CleanupCacheOnOpenFontFileRemoval(this);
        }
	delete iData;
	}

/**
Gets the nearest font in pixels.

Implementations of this pure virtual function should create the COpenFont 
derived object that most closely matches aFontSpec, and place a pointer to 
it in aFont. If this cannot be done, e.g. if the font name doesn't match, 
aFont should be set to NULL. 
	
The other two arguments, aHeap and aSessionCacheList, should be passed to 
the COpenFont constructor.
	
Implementations may use the utilitity function GetNearestFontHelper() to get 
the attributes of the closest matching font.
	
@param aHeap Shared heap. This value should be passed to the COpenFont derived 
classes' constructor.
@param aSessionCacheList The session cache list. This value should be passed 
to the COpenFont derived classes' constructor.
@param aDesiredFontSpec The desired font specification.
@param aPixelWidth The width of a pixel. Used with aPixelHeight for calculating 
the algorithmic slant of the typeface. 
@param aPixelHeight The height of a pixel. Used with aPixelWidth for calculating 
the algorithmic slant of the typeface.
@param aFont On return, contains a pointer to the newly created COpenFont 
derived object, or NULL if no font matching aDesiredFontSpec exists.
@param aActualFontSpec The actual font specification of the font retrieved 
into aFont. 
@see GetNearestFontHelper()
@deprecated Use GetNearestFontToDesignHeightInPixels
*/
TInt COpenFontFile::GetNearestFontInPixels(
	RHeap*						aHeap,
	COpenFontSessionCacheList*	aSessionCacheList,
	const TOpenFontSpec&		aDesiredFontSpec,
	TInt						aPixelWidth,
	TInt						aPixelHeight,
	COpenFont*&					aFont,
	TOpenFontSpec&				aActualFontSpec)
	{
	return GetNearestFontToDesignHeightInPixels(aHeap, aSessionCacheList, aDesiredFontSpec, aPixelWidth, aPixelHeight, aFont, aActualFontSpec);
	}

/**
Gets the nearest font in pixels.

Implementations of this pure virtual function should create the COpenFont 
derived object that most closely matches aFontSpec, and place a pointer to 
it in aFont. If this cannot be done, e.g. if the font name doesn't match, 
aFont should be set to NULL. 
	
The other two arguments, aHeap and aSessionCacheList, should be passed to 
the COpenFont constructor.
	
Implementations may use the utilitity function GetNearestFontHelper() to get 
the attributes of the closest matching font.
	
@param aHeap Shared heap. This value should be passed to the COpenFont derived 
classes' constructor.
@param aSessionCacheList The session cache list. This value should be passed 
to the COpenFont derived classes' constructor.
@param aDesiredFontSpec The desired font specification.
@param aPixelWidth The width of a pixel. Used with aPixelHeight for calculating 
the algorithmic slant of the typeface. 
@param aPixelHeight The height of a pixel. Used with aPixelWidth for calculating 
the algorithmic slant of the typeface.
@param aFont On return, contains a pointer to the newly created COpenFont 
derived object, or NULL if no font matching aDesiredFontSpec exists.
@param aActualFontSpec The actual font specification of the font retrieved 
into aFont. 
@see GetNearestFontHelper()
*/
TInt COpenFontFile::GetNearestFontToDesignHeightInPixels(
	RHeap*						aHeap,
	COpenFontSessionCacheList*	aSessionCacheList,
	const TOpenFontSpec&		aDesiredFontSpec,
	TInt						aPixelWidth,
	TInt						aPixelHeight,
	COpenFont*&					aFont,
	TOpenFontSpec&				aActualFontSpec)
	{
	aFont = NULL;
	TRAPD(error, GetNearestFontToDesignHeightInPixelsAndAddToListL(aHeap, aSessionCacheList, aDesiredFontSpec, aPixelWidth, aPixelHeight, aFont, aActualFontSpec));
	return error;
	}


void COpenFontFile::GetNearestFontToDesignHeightInPixelsAndAddToListL(
	RHeap*						aHeap,
	COpenFontSessionCacheList*	aSessionCacheList,
	const TOpenFontSpec&		aDesiredFontSpec,
	TInt						aPixelWidth,
	TInt						aPixelHeight,
	COpenFont*&					aFont,
	TOpenFontSpec&				aActualFontSpec)
	{
	COpenFont* fontPtr = NULL;
	GetNearestFontToDesignHeightInPixelsL(aHeap, aSessionCacheList, aDesiredFontSpec, aPixelWidth, aPixelHeight, fontPtr, aActualFontSpec);
	if (fontPtr != NULL)
		{ // found a matching font
		CleanupStack::PushL(fontPtr);
		iFontList.AppendL(fontPtr);
		// transfer ownership
		aFont = fontPtr;
		CleanupStack::Pop(fontPtr);
		}
	}


/**
Gets the nearest font in pixels that fits inside specified max height.

Implementations of this pure virtual function should create the COpenFont 
derived object that most closely matches aFontSpec, while fitting within
aMaxHeight, and place a pointer to it in aFont. If this cannot be done,
e.g. if the font name doesn't match, aFont should be set to NULL. 

The other two arguments, aHeap and aSessionCacheList, should be passed to 
the COpenFont constructor.

Implementations may use the utilitity function GetNearestFontHelper()
to get the attributes of the closest matching font.

@param aHeap Shared heap. This value should be passed to the COpenFont derived 
classes' constructor.
@param aSessionCacheList The session cache list. This value should be passed 
to the COpenFont derived classes' constructor.
@param aDesiredFontSpec The desired font specification.
@param aPixelWidth The width of a pixel. Used with aPixelHeight for calculating 
the algorithmic slant of the typeface. 
@param aPixelHeight The height of a pixel. Used with aPixelWidth for calculating 
the algorithmic slant of the typeface.
@param aFont On return, contains a pointer to the newly created COpenFont 
derived object, or NULL if no font matching aDesiredFontSpec exists.
@param aActualFontSpec The actual font specification of the font retrieved 
into aFont. 
@param aMaxHeight The maximum height within which the font must fit.
@see GetNearestFontHelper()
*/
TInt COpenFontFile::GetNearestFontToMaxHeightInPixels(
	RHeap*						aHeap,
	COpenFontSessionCacheList*	aSessionCacheList,
	const TOpenFontSpec&		aDesiredFontSpec,
	TInt						aPixelWidth,
	TInt						aPixelHeight,
	COpenFont*&					aFont,
	TOpenFontSpec&				aActualFontSpec,
	TInt						aMaxHeight)
	{
	aFont = NULL;
	TRAPD(error, GetNearestFontToMaxHeightInPixelsAndAddToListL(aHeap, aSessionCacheList, aDesiredFontSpec, aPixelWidth, aPixelHeight, aFont, aActualFontSpec, aMaxHeight));
	return error;
	}


void COpenFontFile::GetNearestFontToMaxHeightInPixelsAndAddToListL(
	RHeap*						aHeap,
	COpenFontSessionCacheList*	aSessionCacheList,
	const TOpenFontSpec&		aDesiredFontSpec,
	TInt						aPixelWidth,
	TInt						aPixelHeight,
	COpenFont*&					aFont,
	TOpenFontSpec&				aActualFontSpec,
	TInt						aMaxHeight)
	{
	COpenFont* fontPtr = NULL;
	GetNearestFontToMaxHeightInPixelsL(aHeap, aSessionCacheList, aDesiredFontSpec, aPixelWidth, aPixelHeight, fontPtr, aActualFontSpec, aMaxHeight);
	if (fontPtr != NULL)
		{  // found a matching font
		CleanupStack::PushL(fontPtr);
		iFontList.AppendL(fontPtr);
		// transfer ownership
		aFont = fontPtr;
		CleanupStack::Pop(fontPtr);
		}
	}


/**
Gets the nearest font helper function.

This function may be used by derived classes in their GetNearestFontInPixelsL() 
implementations. It finds the nearest font in the typeface attribute array, 
if any, to the provided font specification. If there is a possible match it 
places the face index in aFaceIndex and the actual specification (including 
algorithmic effects) in aActualFontSpec.

@param aDesiredFontSpec The desired font specification.
@param aPixelWidth The width of a pixel. Used with aPixelHeight for calculating 
the algorithmic slant of the typeface.
@param aPixelHeight The height of a pixel. Used with aPixelWidth for calculating 
the algorithmic slant of the typeface.
@param aFaceIndex The index of the typeface which contains the closest match 
to aDesiredFontSpec.
@param aActualFontSpec The actual font specification of the font with attributes 
closest to aDesiredFontSpec.
@return ETrue if there is a possible font match, otherwise EFalse.
*/
EXPORT_C TBool COpenFontFile::GetNearestFontHelper(
	const TOpenFontSpec&	aDesiredFontSpec,
	TInt					aPixelWidth,
	TInt					aPixelHeight,
	TInt&					aFaceIndex,
	TOpenFontSpec&			aActualFontSpec) const
	{
	const TInt faces = FaceCount();
	TInt best_points = 0;
	TInt best_index = -1;

	for (TInt i = 0; i < faces; i++)
		{
		TInt cur_points = 0;

		if (0 < aDesiredFontSpec.Name().Length())
			{
			cur_points = ScoreByName(aDesiredFontSpec, iFaceAttrib[i]);
			}
		else
			{
			cur_points = ScoreByStyle(aDesiredFontSpec, iFaceAttrib[i]);
			}

		if (cur_points)
			{
			if (aDesiredFontSpec.IsItalic() == iFaceAttrib[i].IsItalic())
				cur_points++;
			if (aDesiredFontSpec.IsBold() == iFaceAttrib[i].IsBold())
				cur_points++;
			}

		if (cur_points > best_points)
			{
			best_points = cur_points;
			best_index = i;
			}
		}

	if (best_index != -1)
		{
		aActualFontSpec = aDesiredFontSpec;
		// copy attributes & name
		aActualFontSpec.SetAttrib(iFaceAttrib[best_index]);
		aActualFontSpec.SetName(iFaceAttrib[best_index].FamilyName());
		// Set an algorithmic slant and adjust it for the pixel aspect ratio.
		if ((aDesiredFontSpec.IsItalic()) && (!iFaceAttrib[best_index].IsItalic()) && (0 == aDesiredFontSpec.SlantFactor()))
			{
			TInt factor = KDefaultSlantFactor;
			if (TOpenFontSpec::IsCompensationForAspectRatioNeeded(aPixelWidth, aPixelHeight))
				{
				TOpenFontSpec::ApplyRatio(factor, aPixelWidth, aPixelHeight);
				}
			aActualFontSpec.SetSlantFactor(factor);
			}
		}

	aFaceIndex = best_index;
	return best_index != -1;
	}

TInt COpenFontFile::ScoreByName(const TOpenFontSpec& aDesiredFontSpec, const TAttrib& aAttrib)
	{
	if (!aDesiredFontSpec.Name().CompareF(aAttrib.FullName()) || !aDesiredFontSpec.Name().CompareF(aAttrib.LocalFullName()))
		{
		return 4;
		}
	else if (!aDesiredFontSpec.Name().CompareF(aAttrib.ShortFullName()) || !aDesiredFontSpec.Name().CompareF(aAttrib.ShortLocalFullName()))
		{
		return 3;
		}
	else if (!aDesiredFontSpec.Name().CompareF(aAttrib.FamilyName()) || !aDesiredFontSpec.Name().CompareF(aAttrib.LocalFamilyName()))
		{
		return 2;
		}
	else if (!aDesiredFontSpec.Name().CompareF(aAttrib.ShortFamilyName()) || !aDesiredFontSpec.Name().CompareF(aAttrib.ShortLocalFamilyName()))
		{
		return 1;
		}
	return 0;
	}

TInt COpenFontFile::ScoreByStyle(const TOpenFontSpec& aDesiredFontSpec, const TAttrib& aAttrib)
	{
	if (aDesiredFontSpec.IsSymbol() == aAttrib.IsSymbol())
		{
		return 4;
		}
	else if(aDesiredFontSpec.IsMonoWidth() == aAttrib.IsMonoWidth())
		{
		return 3;
		}
	else if(aDesiredFontSpec.IsSerif() == aAttrib.IsSerif())
		{
		return 2;
		}

	return 0;
	}

#ifdef _DEBUG
/**  @internalComponent */
EXPORT_C TBool COpenFontFile::GetNearestFontHelperOld(const TOpenFontSpec& aDesiredFontSpec, TInt aPixelWidth,TInt aPixelHeight,TInt& aFaceIndex, TOpenFontSpec& aActualFontSpec) const
	{
	TInt faces = FaceCount();
	TInt best_points = 0;
	TInt best_index = -1;
	TBool slant = FALSE;
	for (TInt i = 0; i < faces; i++)
		{
		TPtrC family_name = iFaceAttrib[i].FamilyName();
		TPtrC full_name = iFaceAttrib[i].FullName();
		TPtrC local_family_name = iFaceAttrib[i].LocalFamilyName();
		TPtrC local_full_name = iFaceAttrib[i].LocalFullName();
		TPtrC desired_name = aDesiredFontSpec.Name();

		TInt cur_points = 0;
		if (desired_name.Length() > 0)
			{
			if ((full_name.CompareF(desired_name) == 0) || (local_full_name.CompareF(desired_name) == 0))
				cur_points = 4;
			else if ((family_name.CompareF(desired_name) == 0) || (local_family_name.CompareF(desired_name) == 0))
				cur_points = 2;
			}
		else
			{
			if ((aDesiredFontSpec.IsSerif() == iFaceAttrib[i].IsSerif()) && (aDesiredFontSpec.IsMonoWidth() == iFaceAttrib[i].IsMonoWidth()) && (aDesiredFontSpec.IsSymbol() == iFaceAttrib[i].IsSymbol()))
				cur_points = 2;
			}
		if (cur_points)
			{
			if (aDesiredFontSpec.IsItalic() == iFaceAttrib[i].IsItalic())
				cur_points++;
			if (aDesiredFontSpec.IsBold() == iFaceAttrib[i].IsBold())
				cur_points++;
			if (cur_points > best_points)
				{
				best_points = cur_points;
				best_index = i;
				slant = (aDesiredFontSpec.IsItalic()) && (!iFaceAttrib[i].IsItalic());
				}
			}
		}

	if (best_index != -1)
		{
		TInt32 slant_factor = aDesiredFontSpec.SlantFactor();

		// Set an algorithmic slant and adjust it for the pixel aspect ratio.
		if (slant && slant_factor == 0)
			{
			slant_factor = KDefaultSlantFactor;
			if (aPixelWidth>0 && aPixelHeight>0 && TOpenFontSpec::IsCompensationForAspectRatioNeeded(aPixelWidth,aPixelHeight))
				{
				TOpenFontSpec::ApplyRatio(slant_factor,aPixelWidth,aPixelHeight);
				}
			}

		aActualFontSpec = aDesiredFontSpec;
		// copy attributes & name
		aActualFontSpec.SetAttrib(iFaceAttrib[best_index]);
		aActualFontSpec.SetName(iFaceAttrib[best_index].FamilyName());
		aActualFontSpec.SetSlantFactor(slant_factor);
		aActualFontSpec.SetEffects(0);
		}

	aFaceIndex = best_index;
	return best_index != -1;
	}
#else //_DEBUG
/**
@internalComponent
*/
EXPORT_C TBool COpenFontFile::GetNearestFontHelperOld(const TOpenFontSpec&, TInt, TInt, TInt&, TOpenFontSpec&) const 
	{
	return EFalse;
	}
#endif //_DEBUG

/** This function is called (via iFile) by a COpenFont when it is destroyed. */
void COpenFontFile::RemoveFontFromList(const COpenFont* aFont)
	{
	TInt fonts = iFontList.Count();
	for (TInt i = 0; i < fonts; i++)
		if (iFontList[i] == aFont)
			{
			iFontList.Delete(i);
			break;
			}
	}

/**
Adds a typeface to this object's typeface array.

This function should be called during construction to add the attributes for 
each typeface in the font file to the typeface attribute array. 

Note:

The typeface array is what is searched for the closest match to a specified 
font by GetNearestFontHelper().

@param aAttrib The attributes for a typeface to be added to the typeface attribute 
array.
@see FaceAttrib()
@see FaceCount()
*/
EXPORT_C void COpenFontFile::AddFaceL(const TOpenFontFaceAttrib& aAttrib)
	{
	TAttrib& a = iFaceAttrib.ExtendL();
	(TOpenFontFaceAttrib&)a = aAttrib;
	}

void COpenFontFile::SetFontStoreL(CFontStore* aFontStore)
	{
	if (!iData)
		{
		iData = new (ELeave) TOpenFontFileData;
		}
	iData->iFontStore = aFontStore;
	}

CFontStore* COpenFontFile::GetFontStore()
	{
	return iData ? iData->iFontStore : NULL;
	}

CArrayPtrFlat<COpenFont>* COpenFontFile::GetOpenFontList()
	{
	return &iFontList;
	}


static const TInt KTOpenFontSpecBitsNumSymbol = 1;
static const TInt KTOpenFontSpecBitsNumScript = 4;
static const TInt KTOpenFontSpecMaskSymbol = (1 << KTOpenFontSpecBitsNumSymbol) - 1;
static const TInt KTOpenFontSpecMaskScript = ((1 << KTOpenFontSpecBitsNumScript) - 1) << KTOpenFontSpecBitsNumSymbol;
static const TInt KTOpenFontSpecSymbolFlag = 0x1;

/**
Default C++ constructor setting
height to 16 pixels or twips,
width factor to 1 (65536 in 16.16 format),
slant factor to 0 (no slant),
effects to ENone,
symbol to 0 (assuming EScriptNone = 0),
print position to EPrintPosNormal.
*/
EXPORT_C TOpenFontSpec::TOpenFontSpec()
 :	iHeight(16),
	iWidthFactor(KOneIn16Dot16FixedPointFormat),
	iSlantFactor(0),
	iBitmapType(0),
	iEffects(FontEffect::ENone),
	iSymbol(0),
	iPrintPosition(EPrintPosNormal),
	iReserved2(0)
	{
	}

/**
C++ constructor taking a reference to a TFontSpec.

This object's members are initialised from the values of the aFontSpec parameter.

@param aFontSpec The font specification used to initialise this font specification.
*/
EXPORT_C TOpenFontSpec::TOpenFontSpec(const TFontSpec& aFontSpec)
	{
	*this = aFontSpec;
	}

/**
Assignment operator.

@param aFontSpec The old-style font specification to copy into this font specification.
*/
EXPORT_C void TOpenFontSpec::operator=(const TFontSpec& aFontSpec)
	{
	iSlantFactor = 0;
	iWidthFactor = KOneIn16Dot16FixedPointFormat;
	iHeight			= aFontSpec.iHeight;	// in twips
	iBitmapType		= aFontSpec.iFontStyle.BitmapType();
	iEffects		= aFontSpec.iFontStyle.Effects();
	iPrintPosition	= aFontSpec.iFontStyle.PrintPosition();
	iName			= aFontSpec.iTypeface.iName;
	SetScriptTypeForMetrics(aFontSpec.iTypeface.ScriptTypeForMetrics());
	const TBool symbol = aFontSpec.iTypeface.IsSymbol();
	SetSymbol(symbol);
	if (symbol)
		SetCoverage(0);	// no appropriate coverage value for the symbol set
	else
		SetCoverage(3);	// Latin and Latin-1 supplement
	iStyle = 0;
	if (!aFontSpec.iTypeface.IsProportional())
		iStyle |= TOpenFontFaceAttrib::EMonoWidth;
	if (aFontSpec.iTypeface.IsSerif())
		iStyle |= TOpenFontFaceAttrib::ESerif;
	if (aFontSpec.iFontStyle.Posture() == EPostureItalic)
		iStyle |= TOpenFontFaceAttrib::EItalic;
	if (aFontSpec.iFontStyle.StrokeWeight() == EStrokeWeightBold)
		iStyle |= TOpenFontFaceAttrib::EBold;
	}


/**
Adjust the width factor and slant factor to suit a pixel aspect ratio.
@publishedAll
@released
@param aPixelWidth The pixel width, in the same units as aPixelHeight.
@param aPixelHeight The pixel height, in the same units as aPixelWidth.
*/
EXPORT_C void TOpenFontSpec::CompensateForAspectRatio(TInt aPixelWidth, TInt aPixelHeight)
	{
	if (IsCompensationForAspectRatioNeeded(aPixelWidth, aPixelHeight))
		{
		ApplyRatio(iWidthFactor, aPixelHeight, aPixelWidth);
		ApplyRatio(iSlantFactor, aPixelWidth, aPixelHeight);
		}
	}

/**
Adjust the width factor and slant factor to suit a pixel aspect ratio stored 
in a MGraphicsDeviceMap derived object.
@publishedAll
@released
@param aMap The MGraphicsDeviceMap defining the pixel aspect ratio.
*/
EXPORT_C void TOpenFontSpec::CompensateForAspectRatio(const MGraphicsDeviceMap& aMap)
	{
	CompensateForAspectRatio(aMap.HorizontalPixelsToTwips(1000), aMap.VerticalPixelsToTwips(1000));
	}

/**
The pixel width and height are used to derive a ratio, and so can be 
in any units. Aspect ratios differing by less than 1/1000 are treated as 1:1.
@internalTechnology
*/
TBool TOpenFontSpec::IsCompensationForAspectRatioNeeded(TInt aPixelWidth,TInt aPixelHeight)
	{
	if ((aPixelWidth != aPixelHeight) && (0 < aPixelWidth) && (0 < aPixelHeight))
		{
		//If nearly square don't transform (0.999 < aPixelHeight/aPixelWidth < 1.001)
		TInt64 width = aPixelWidth;
		TInt64 height = aPixelHeight;
		width *= 999;	// Cannot do multiplication on declaration lines above as risk of TInt32 overflow
		height *= 1000;
		if (width <= height)	// 999 * aPixelWidth <= 1000 * aPixelHeight
			return ETrue;
		width += aPixelWidth;
		width += aPixelWidth;	// Cannot do with previous line as small risk of TInt32 overflow
		if (width >= height)	// 1001 * aPixelWidth >= 1000 * aPixelHeight
			return ETrue;
		}
	return EFalse;
	}

/**
Multiplies aValue by aNumerator/aDenominator but using TInt64's to avoid any overflows.
Returns ETrue if the final result has an overflow.
@internalTechnology
*/
TBool TOpenFontSpec::ApplyRatio(TInt& aValue, TInt aNumerator, TInt aDenominator)
	{
	TInt64 value(aValue);
	value = (value * aNumerator) / aDenominator;
	aValue = I64LOW(value);
	__ASSERT_DEBUG(I64HIGH(value) == 0, Panic(EFntOverFlow));
	return I64HIGH(value) != 0;
	}

/**
Same as above function but this takes a TInt32 not a TInt
*/
TBool TOpenFontSpec::ApplyRatio(TInt32& aValue, TInt aNumerator, TInt aDenominator)
	{
	TInt value = aValue;
	TBool ret = ApplyRatio(value, aNumerator, aDenominator);
	aValue = value;
	return ret;
	}

EXPORT_C void TOpenFontSpec::SetAttrib(const TOpenFontFaceAttribBase& aAttrib)
/**
Sets the font attributes.

@param aAttrib The font attributes.
*/
	{
	TOpenFontFaceAttribBase* self = this;
	*self = aAttrib;
	}

/**
Gets the TFontSpec corresponding to this Open Font System font specification.
@publishedAll
@released
@param aFontSpec On return, contains the TFontSpec corresponding to this font 
specification.
*/
EXPORT_C void TOpenFontSpec::GetTFontSpec(TFontSpec& aFontSpec) const
	{
	aFontSpec = TFontSpec();
	TPtrC short_name(iName.Ptr(), Min(iName.Length(), KMaxTypefaceNameLength));
	aFontSpec.iTypeface.iName = short_name;
	aFontSpec.iTypeface.SetIsProportional(!IsMonoWidth());
	aFontSpec.iTypeface.SetIsSerif(IsSerif());
	aFontSpec.iTypeface.SetIsSymbol(Symbol());
	aFontSpec.iTypeface.SetScriptTypeForMetrics(ScriptTypeForMetrics());
	aFontSpec.iHeight = iHeight;	// as twips
	if (IsItalic() || (iSlantFactor > 0))
		aFontSpec.iFontStyle.SetPosture(EPostureItalic);
	if (IsBold() || IsEffectOn(FontEffect::EAlgorithmicBold))
		aFontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold);
	aFontSpec.iFontStyle.SetPrintPosition(iPrintPosition);
	aFontSpec.iFontStyle.SetBitmapType(BitmapType());
	aFontSpec.iFontStyle.SetEffects(iEffects);
	}

/**
Sets a font effect to the given state.
@publishedAll
@released
@param aEffect The font effect to be set.
@param aOn True represents on, otherwise off.
@see TOpenFontSpec::IsEffectOn()
*/
EXPORT_C void TOpenFontSpec::SetEffects(FontEffect::TEffect aEffect, TBool aOn)
	{
	FontEffect::SetEffect(aEffect, aOn, iEffects);
	}

/** Checks if a font effect is on.
@publishedAll
@released
@return True represents the specified font effect is on, otherwise off.
@param aEffect The font effect to be checked.
@see TOpenFontSpec::SetEffects()
*/
EXPORT_C TBool TOpenFontSpec::IsEffectOn(FontEffect::TEffect aEffect) const
	{
	return FontEffect::IsEffectOn(aEffect, iEffects);
	}

/**
@deprecated This needs to be maintained to just call the inline methods.
*/
EXPORT_C void TOpenFontSpec::DoSetEffects(TUint32 aEffects)
	{
	SetEffects(aEffects);
	}

/**
@deprecated This needs to be maintained to just call the inline methods.
*/
EXPORT_C TUint32 TOpenFontSpec::DoEffects() const
	{
	return Effects();
	}

/**
Specifies the script which font metrics calculation will be based on.
@publishedAll
@released
@param aLanguage The language used to derive the required script.
*/
EXPORT_C void TOpenFontSpec::SetScriptTypeForMetrics(TLanguage aLanguage)
	{
	SetScriptTypeForMetrics(GlyphSample::TLanguage2TScript(aLanguage));
	}

/**
@internalTechnology
*/
void TOpenFontSpec::SetScriptTypeForMetrics(TInt aScript)
	{
	iSymbol &= ~KTOpenFontSpecMaskScript;
	iSymbol |= (KTOpenFontSpecMaskScript & (aScript << KTOpenFontSpecBitsNumSymbol));
	}

/**
Gets the script which the font metrics calculation will be based on.
@internalTechnology
@return The script.
*/
EXPORT_C TInt TOpenFontSpec::ScriptTypeForMetrics() const
	{
	return (KTOpenFontSpecMaskScript & iSymbol) >> KTOpenFontSpecBitsNumSymbol;
	}

/**
@internalTechnology
*/
void TOpenFontSpec::SetSymbol(TBool aSymbol)
	{
	iSymbol &= ~KTOpenFontSpecMaskSymbol;
	iSymbol |= (aSymbol ? KTOpenFontSpecSymbolFlag : 0);
	}

/**
@internalTechnology
*/
TBool TOpenFontSpec::Symbol() const
	{
	return (KTOpenFontSpecSymbolFlag & iSymbol) > 0;
	}

/**
@deprecated This needs to be maintained to just call the inline methods.
*/
EXPORT_C TBool TOpenFontSpec::OperatorEquality(const TOpenFontSpec& aOpenFontSpec) const
	{
	return this->operator == (aOpenFontSpec);
	}

/**
@internalTechnology
*/
TBool TOpenFontSpec::operator!=(const TOpenFontSpec& aOpenFontSpec) const
	{
	return !(this->operator == (aOpenFontSpec));
	}

/**
Static constructor for a TOpenFontGlyphData.

This constructor creates the object on a specified heap. It must be deleted 
using RHeap::Free().

@param aHeap The shared heap on which the object is constructed.
@param aBufferSize The amount of memory allocated for the glyph data.
@return A pointer to the newly created object.
*/
EXPORT_C TOpenFontGlyphData* TOpenFontGlyphData::New(RHeap* aHeap, TInt aBufferSize)
	{
	if (aBufferSize < 1)
		aBufferSize = 1;
	TInt bytes = sizeof(TOpenFontGlyphData) + aBufferSize - 1;
	TOpenFontGlyphData* g = (TOpenFontGlyphData*)aHeap->Alloc(bytes);
	if (g)
		{
		Mem::FillZ(g, bytes);
		g->iBitmapBufferSize = aBufferSize;
		}
	return g;
	}

// Virtual functions reserved for future expansion.
/**
@publishedPartner
@prototype
*/
EXPORT_C void COpenFontRasterizer::ExtendedInterface(TUid, TAny*&)
	{
	}

/** @internalComponent */
EXPORT_C void COpenFontFile::ExtendedInterface(TUid, TAny*&)
	{
	}

EXPORT_C void COpenFont::ExtendedInterface(TUid, TAny*&)
	{
	}
	
EXPORT_C CShaper::CShaper()
	{
	
	}
	
EXPORT_C CShaper::~CShaper()
	{
	
	}
/** @internalComponent */
EXPORT_C void* CShaper::ExtendedInterface(TUid)
	{
	return 0;
	}

/**
Sets the glyph bitmap type.

Normally the bitmap type belongs to the font, but for linked fonts this can 
be different between different font elements making up the linked font.

Note: This is only of use in conjunction with rasterizer based linked fonts.

@publishedPartner
@prototype
*/
EXPORT_C void TOpenFontCharMetrics::SetGlyphType(TGlyphBitmapType aGlyphBitmapType)
	{
	iGlyphBitmapType = aGlyphBitmapType;
	}

/**
Gets the glyph bitmap type.

@publishedPartner
@prototype
*/
EXPORT_C TGlyphBitmapType TOpenFontCharMetrics::GlyphType() const
	{
	if (iGlyphBitmapType == 0)
		return EGlyphBitmapTypeNotDefined;
	else
		return static_cast<TGlyphBitmapType>(iGlyphBitmapType);
	}