fontservices/freetypefontrasteriser/src/FTRAST2.CPP
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 12 Mar 2010 15:51:09 +0200
branchRCL_3
changeset 11 6971d1c87c9a
parent 0 1fb32624e06b
child 54 748ec5531811
permissions -rw-r--r--
Revision: 201007 Kit: 201008

/*
* Copyright (c) 1998-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: 
* FTRAST.CPP
* Wrapper code to connect FreeType with the EPOC rasterizer framework.
* This version uses FreeType 2.2.1
* Secure Rasterizer Plugin. The rasterizer is now implemented as 
* an ECOM Plugin. Secure FBServ uses ECOM APIs provided to load the 
* plugin.
*
*/


#include <e32uid.h>
#include <f32file.h>
#include <charconv.h>
#include <sys/reent.h>
#include <openfont.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_INTERNAL_TRUETYPE_TYPES_H
#include <ftsnames.h>
#include <ecom/ecom.h>
#include <ecom/implementationproxy.h>
#include <gdi.h>
#include <e32hashtab.h>
#include <graphics/openfontrasterizer.h>
#include <graphics/gdi/glyphsample.h>
#include <graphics/openfontconstants.h>

static const TInt KOneIn16Dot16FixedPointFormat = 65536;

class CFreeTypeContext;

class CFreeTypeRasterizer : public COpenFontRasterizer
	{
public:
	static COpenFontRasterizer* NewL();
	virtual ~CFreeTypeRasterizer();
	// COpenFontRasterizer implementation
	COpenFontFile* NewFontFileL(TInt aUid, const TDesC& aFileName, RFs& aFileSession);
private:
	CFreeTypeRasterizer();
private:
	CFreeTypeContext* iContext;
	};

NONSHARABLE_CLASS(CFaceListItem) : public CBase
	{
	friend class CFaceList;
public:
	virtual ~CFaceListItem();
	static CFaceListItem* NewL(CFreeTypeContext* aContext, const TText8* aFileName, TInt aFaceIndex);
	void SetFaceNamesL(TOpenFontFaceAttrib& aAttrib) const;
	void GetBiggestGlyphsFromSampleL(
		TInt aScript, TInt& aUnicodeAscender, TInt& aUnicodeDescender) const;
	TBool LoadGlyphAndGetAscenderDescender(
		TUint32 aCode, TInt32& aAscender, TInt32& aDescender) const;
	TInt DeriveDesignHeightFromMaxHeightWithGlyphSampleL(
		TInt aMaxHeightInPixel, TInt aUnicodeAscender, TInt aUnicodeDescender) const;
	TInt DeriveDesignHeightFromMaxHeightWithBBoxL(TInt aMaxHeightInPixel) const;
	FT_Face Face(void) const;
private:
	static void GetDesiredLocalLanguageAndMask(TUint16& aDesiredLocalLanguage, TUint16& aLocalLanguageMask);
	static TInt CopyName(TInt aDestMaxLen, TUint16* aDest, const TUint8* aSrc);
	CFaceListItem();
	void ConstructL(CFreeTypeContext* aContext, const TText8* aFileName, TInt aFaceIndex);
	TInt GetFamilyAndStyleNames(TInt aDestMaxLen, TUint16* aDest, TInt& aFamilyNameLen) const;
	void SetTTFFaceNamesL(TOpenFontFaceAttrib& aAttrib) const;
private:
	CFaceListItem*	iNext;
	const TText8*	iFileName;	// owned by the CFreeTypeFontFile object
	TInt			iFaceIndex;
	FT_Face			iFace;
	};

NONSHARABLE_CLASS(CFaceList) : public CBase
	{
public:
	CFaceList();
	virtual ~CFaceList();
	CFaceListItem* LoadFaceL(CFreeTypeContext* aContext, const TText8* aFileName, TInt aFaceIndex);
	void DeleteFace(const TText8* aFileName, TInt aFaceIndex);
private:
	static TInt MemoryUsed(void);
	void DeleteLastFace(void);
private:
	/*
	The memory threshold is not an absolute limit because we must allow
	at least one typeface to be loaded, but if it is exceeded typefaces
	will be unloaded until just one is left (the one being used) or until
	the memory available no longer exceeds the threshold.
	*/
	enum
		{
		EMemoryThreshold = 1024 * 1024
		};

	CFaceListItem* iFirstItem;
	};

NONSHARABLE_CLASS(CFreeTypeContext) : public COpenFontRasterizerContext
	{
public:
	static CFreeTypeContext* NewL();
	virtual ~CFreeTypeContext();
	void TranslateMonochromeGlyphBitmap (FT_GlyphSlot aGlyphSlot, TOpenFontGlyphData* aGlyphData);
	void TranslateAntiAliasedGlyphBitmap(FT_GlyphSlot aGlyphSlot, TOpenFontGlyphData* aGlyphData);
	FT_Library Library(void) const;
	CFaceListItem* LoadFaceL(const TText8* aFileName, TInt aFaceIndex);
	void DeleteFace(const TText8* aFileName, TInt aFaceIndex);
private:
	void ConstructL(void);
	void WriteMonoData(TUint8 aData, TInt aBitCount);
private:
	FT_Library iLibrary;
	CFaceList iFaceList;
	};

NONSHARABLE_CLASS(CFreeTypeFontFile) : public COpenFontFile
	{
public:
	static CFreeTypeFontFile* NewL(
		CFreeTypeContext* aContext, TInt aUid, const TDesC& aFileName, RFs& aFileSession);
	virtual ~CFreeTypeFontFile();
	CFaceListItem* LoadFaceL(TInt aFaceIndex);
	CFaceListItem* LoadFaceAndSetTransformL(TInt aFaceIndex,
		TInt aSizeInPixels, TInt32 aWidthFactor, TInt32 aSlantFactor);
	void RasterizeL(
		TInt aCode, TInt aFaceIndex, TInt aSizeinPixels, TInt32 aWidthFactor, 
		TInt32 aSlantFactor, TGlyphBitmapType aBitmapType, TOpenFontGlyphData* aGlyphData);
	void RasterizeGlyphL(
		TInt aCode, TInt aFaceIndex, TInt aSizeInPixels, TInt32 aWidthFactor,
		TInt32 aSlantFactor, TGlyphBitmapType aBitmapType, TOpenFontGlyphData* aGlyphData);
	// COpenFontFile implementation
	void GetNearestFontInPixelsL(
		RHeap* aHeap, COpenFontSessionCacheList* aSessionCacheList,
		const TOpenFontSpec& aDesiredFontSpec, TInt aPixelWidth, TInt aPixelHeight,
		COpenFont*& aFont, TOpenFontSpec& aActualFontSpec);
	void GetNearestFontToDesignHeightInPixelsL(
		RHeap* aHeap, COpenFontSessionCacheList* aSessionCacheList,
		const TOpenFontSpec& aDesiredFontSpec, TInt aPixelWidth, TInt aPixelHeight,
		COpenFont*& aFont, TOpenFontSpec& aActualFontSpec);
	void GetNearestFontToMaxHeightInPixelsL(
		RHeap* aHeap, COpenFontSessionCacheList* aSessionCacheList,
		const TOpenFontSpec& aDesiredFontSpec, TInt aPixelWidth, TInt aPixelHeight,
		COpenFont*& aFont, TOpenFontSpec& aActualFontSpec, TInt aMaxHeight);
	TBool HasUnicodeCharacterL(TInt aFaceIndex, TInt aCode) const;
	TAny* GetTrueTypeTable(TInt& aError, TInt aFaceIndex, TUint32 aTag, TInt* aLength);

private:
	static void SetGlyphMetrics(FT_GlyphSlot aGlyphSlot, TOpenFontGlyphData* aGlyphData);
	void GetNearestFontInPixelsL(
		RHeap* aHeap, COpenFontSessionCacheList* aSessionCacheList,
		const TOpenFontSpec& aDesiredFontSpec, TInt aPixelWidth, TInt aPixelHeight,
		COpenFont*& aFont, TOpenFontSpec& aActualFontSpec, TInt aMaxHeight);
	CFreeTypeFontFile(TInt aUid, const TDesC& aFileName);
	void ConstructL(CFreeTypeContext* aContext, const TDesC& aFileName, RFs& aFileSession);
	void CreateFilenameInUTF8L(const TDesC& aFileName, RFs& aFileSession);
	static TUint32 TagHash(const TUint32& aTag);
	static TBool TagId(const TUint32& aTag1, const TUint32& aTag2);

	void DoRasterizeGlyphL(TInt aCode, const CFaceListItem* aFace,
		TGlyphBitmapType aBitmapType, TOpenFontGlyphData* aGlyphData);

private:
	CFreeTypeContext* iContext;
	TText8* iFileName; // in null-terminated UTF8 so that it can be passed to fopen
	RHashMap<TUint32, TPtrC8> iTableStore;
	};

NONSHARABLE_CLASS(CFreeTypeFont) : public COpenFont, public MOpenFontShapingExtension, 
    public MOpenFontTrueTypeExtension
	{
public:
	static CFreeTypeFont* NewL(
		RHeap* aHeap, COpenFontSessionCacheList* aSessionCacheList, CFreeTypeFontFile* aFontFile,
		TInt aFaceIndex, TInt aSizeInPixels, TInt32 aWidthFactor, TInt32 aSlantFactor,
		TGlyphBitmapType aBitmapType, TInt aMaxHeight, TInt aScript);
	// COpenFont implementation
	void RasterizeL(TInt aCode, TOpenFontGlyphData* aGlyphData);
private:
	CFreeTypeFont(
		RHeap* aHeap, COpenFontSessionCacheList* aSessionCacheList, CFreeTypeFontFile* aFontFile,
		TInt aFaceIndex, TInt32 aWidthFactor, TInt32 aSlantFactor, TGlyphBitmapType aBitmapType);
	void ConstructL(TInt aSizeInPixels, TInt aMaxHeight, TInt aScript);
	void ComputeMetrics(const FT_Face& aFace, TInt aSizeInPixels, TInt aUnicodeAscender, TInt aUnicodeDescender);
	void ComputeMaxWidth(const FT_Face& aFace);

	// Overload to access extended API
	void ExtendedInterface(TUid aUid, TAny*& aParam);

	// virtual functions from MOpenFontShapingExtension
	void RasterizeGlyphL(TInt aCode,TOpenFontGlyphData* aGlyphData);
	TInt GlyphIndex(TInt aUnicodeCharacter) const;
	TBool GlyphPointInHintedPixels(TInt aGlyphIndex, TInt aPointNumber,
		TReal& aX, TReal& aY) const;
	TBool GlyphPointInFontUnits(TInt aGlyphIndex, TInt aPointNumber,
		TInt& aX, TInt& aY) const;
	void GetExtensionFontMetrics(
		MOpenFontShapingExtension::TExtensionFontMetrics& aOut);

	// virtual functions from MOpenFontTrueTypeExtension
	TAny* GetTrueTypeTable(TInt& aError, TUint32 aTag, TInt* aLength);
	TInt  ReleaseTrueTypeTable(TAny* aTable);
	TBool HasTrueTypeTable(TUint32 aTag);

	inline TAny* operator new(TUint aSize, TAny* aBase) __NO_THROW;
	inline TAny* operator new(TUint aSize) __NO_THROW;
	inline void operator delete(void*, TAny*) __NO_THROW;
	inline void operator delete(void*) __NO_THROW;

private:
	TInt32 iWidthFactor;				// algorithmic width factor as a 16.16 fixed-point number
	TInt32 iSlantFactor;				// algorithmic slant factor as a 16.16 fixed-point number
	TGlyphBitmapType iBitmapType;
	};

#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
#warning Using patented technology!
#endif

inline TAny* CFreeTypeFont::operator new(TUint aSize, TAny* aBase) __NO_THROW
	{ return CBase::operator new(aSize, aBase); }
inline TAny* CFreeTypeFont::operator new(TUint aSize) __NO_THROW
	{ return CBase::operator new(aSize); }

inline void CFreeTypeFont::operator delete(void*, TAny*) __NO_THROW {}
inline void CFreeTypeFont::operator delete(void* a) __NO_THROW
	{
	// We happen to know that the constructor of CFreeTypeFont
	// will always set iHeap correctly before any leave.
	// We would be less certain of this in standard C++ where
	// constructors (and even initializer lists) may throw exceptions.
	CFreeTypeFont* f = reinterpret_cast<CFreeTypeFont*>(a);
	f->iHeap->Free(a);
	}

TInt CFaceList::MemoryUsed()
	{
	TInt total;
	User::AllocSize(total);
	return total;
	}

CFreeTypeContext* CFreeTypeContext::NewL()
	{
	CFreeTypeContext* context = new(ELeave) CFreeTypeContext;
	CleanupStack::PushL(context);
	context->ConstructL();
	CleanupStack::Pop();
	return context;
	}

void CFreeTypeContext::ConstructL()
	{
	if (FT_Init_FreeType(&iLibrary))
		{
		iLibrary = NULL;
		User::Leave(KErrNoMemory);
		}
	}

CFreeTypeContext::~CFreeTypeContext()
	{
	FT_Done_FreeType(iLibrary);
	}

FT_Library CFreeTypeContext::Library() const
	{
	return iLibrary;
	}

CFaceListItem* CFreeTypeContext::LoadFaceL(const TText8* aFileName, TInt aFaceIndex)
	{
	return iFaceList.LoadFaceL(this, aFileName, aFaceIndex);
	}

void CFreeTypeContext::DeleteFace(const TText8* aFileName, TInt aFaceIndex)
	{
	iFaceList.DeleteFace(aFileName, aFaceIndex);
	}

COpenFontRasterizer* CFreeTypeRasterizer::NewL()
	{
	CFreeTypeRasterizer* r = new(ELeave) CFreeTypeRasterizer;
	CleanupStack::PushL(r);
	r->iContext = CFreeTypeContext::NewL();
	CleanupStack::Pop();
	return r;
	}

CFreeTypeRasterizer::CFreeTypeRasterizer()
	{
	}

CFreeTypeRasterizer::~CFreeTypeRasterizer()
	{
	delete iContext;
	CloseSTDLIB();
	}

COpenFontFile* CFreeTypeRasterizer::NewFontFileL(TInt aUid, const TDesC& aFileName, RFs& aFileSession)
	{
	if (4 < aFileName.Length())
		{
		// Allow TrueType fonts
		_LIT(KFntStoreTrueTypeExtension,".ttf");
		// Allow OpenType fonts
		_LIT(KFntStoreOpenTypeExtension,".otf");
		TPtrC16 extension = aFileName.Right(4);
		if (0 == extension.CompareF(KFntStoreTrueTypeExtension)
			|| 0 == extension.CompareF(KFntStoreOpenTypeExtension))
			return CFreeTypeFontFile::NewL(iContext, aUid, aFileName, aFileSession);
		}
	return NULL;
	}

// Exported proxy for instantiation method resolution
// Define the interface UIDs
const TImplementationProxy ImplementationTable[] = 
	{
	IMPLEMENTATION_PROXY_ENTRY(0x101f7f5e, CFreeTypeRasterizer::NewL)
	};

EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
	{
	aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
	return ImplementationTable;
	}

CFaceListItem* CFreeTypeFontFile::LoadFaceL(TInt aFaceIndex)
	{
	return iContext->LoadFaceL(iFileName, aFaceIndex);
	}

CFaceListItem* CFreeTypeFontFile::LoadFaceAndSetTransformL(TInt aFaceIndex,
	TInt aSizeInPixels, TInt32 aWidthFactor, TInt32 aSlantFactor)
	{
	CFaceListItem* face = iContext->LoadFaceL(iFileName, aFaceIndex);
	if (FT_Set_Pixel_Sizes(face->Face(), aSizeInPixels, aSizeInPixels))
		{
		User::Leave(KErrGeneral);
		}
	
	if (aWidthFactor != 0 &&
		(aWidthFactor != KOneIn16Dot16FixedPointFormat || aSlantFactor != 0))
		{
		FT_Matrix matrix;
		matrix.xx = aWidthFactor;
		matrix.xy = aSlantFactor;
		matrix.yx = 0;
		matrix.yy = KOneIn16Dot16FixedPointFormat;
		FT_Set_Transform(face->Face(),&matrix,NULL);
		}
	else
		FT_Set_Transform(face->Face(),NULL,NULL);
	return face;
	}


CFreeTypeFontFile* CFreeTypeFontFile::NewL(CFreeTypeContext* aContext, TInt aUid, const TDesC& aFileName, RFs& aFileSession)
	{
	CFreeTypeFontFile* f = new(ELeave) CFreeTypeFontFile(aUid, aFileName);
	CleanupStack::PushL(f);
	f->ConstructL(aContext, aFileName, aFileSession);
	CleanupStack::Pop();
	return f;
	}

/** Forms a hash value from a TrueType-style tag.
@param aTag
	Each byte will contain a lower-case ASCII value (or possibly a number).
@return
	Hash value. Because we want to avoid collisions, we will move the bottom
	four bits of all four bytes into non-overlapping positions. */
TUint32 CFreeTypeFontFile::TagHash(const TUint32& aTag)
	{
	TUint32 t = aTag;
	// The most useful bits are in the bottom nybbles of each byte
	t ^= t >> 12 | t << 20;
	return t ^ (t << 15 | t >> 17);
	}

TBool CFreeTypeFontFile::TagId(const TUint32& aTag1, const TUint32& aTag2)
	{
	return aTag1 == aTag2;
	}

CFreeTypeFontFile::CFreeTypeFontFile(TInt aUid, const TDesC& aFileName):
	COpenFontFile(aUid, aFileName),
	iTableStore(THashFunction32<TUint32>(CFreeTypeFontFile::TagHash),
		TIdentityRelation<TUint32>(CFreeTypeFontFile::TagId))
	{
	}

CFreeTypeFontFile::~CFreeTypeFontFile()
	{
	const TInt faces = FaceCount();
	for (TInt i = 0; i < faces; i++)
		iContext->DeleteFace(iFileName, i);
	delete[] iFileName;
	THashMapIter<TUint32, TPtrC8> it(iTableStore);
	it.NextValue();
	while (it.CurrentValue())
		{
		delete it.CurrentValue()->Ptr();
		it.NextValue();
		}
	iTableStore.Close();
	}

void CFreeTypeFontFile::ConstructL(CFreeTypeContext* aContext, const TDesC& aFileName, RFs& aFileSession)
	{
	iContext = aContext;

	CreateFilenameInUTF8L(aFileName, aFileSession);

	// Get the filename as a fallback for the typeface name.
	TParse p;
	p.Set(aFileName, NULL, NULL);
	const TPtrC name = p.Name();

	// Load the properties of all the faces in the file.
	//
	// A file may contain one face (e.g. TTF - TrueType Font) or many (e.g. TTC - TrueType Collection).
	// The number is determined from a value stored in the properties of the first face.
	//
	for (TInt face_index = 0, faces = 1; face_index < faces; face_index++)
		{
		// Load the face.
		const CFaceListItem* face = iContext->LoadFaceL(iFileName, face_index);

		// If this is the first face, get the total number of faces.
		if (face_index == 0)
			{
			faces = face->Face()->num_faces;
			if (faces < 1)
				User::Leave(KErrGeneral);
			}

		// Set the face names to the filename as a fallback in case SetFaceNameL doesn't find appropriate names.
		TOpenFontFaceAttrib attrib;
		attrib.SetFullName(name);
		attrib.SetFamilyName(name);
		attrib.SetLocalFullName(name);
		attrib.SetLocalFamilyName(name);

		// Set the face names to those stored in the file if possible.
		face->SetFaceNamesL(attrib);

		// Set the face attributes exposed via FT_Face.
		attrib.SetBold(FT_STYLE_FLAG_BOLD & face->Face()->style_flags);
		attrib.SetItalic(FT_STYLE_FLAG_ITALIC & face->Face()->style_flags);
		attrib.SetMonoWidth(FT_FACE_FLAG_FIXED_WIDTH & face->Face()->face_flags);

		// Set attributes present in TrueType information but not exposed via FT_Face.
		if (FT_FACE_FLAG_SFNT & face->Face()->face_flags)
			{
			const TT_Face tt_face = (TT_Face) face->Face();
			attrib.SetMinSizeInPixels(tt_face->header.Lowest_Rec_PPEM);
			attrib.SetCoverage(tt_face->os2.ulUnicodeRange1,tt_face->os2.ulUnicodeRange2,
							   tt_face->os2.ulUnicodeRange3,tt_face->os2.ulUnicodeRange4);
			const TInt serif_style = tt_face->os2.panose[1];
			attrib.SetSerif((serif_style >= 2 && serif_style <= 10) || serif_style >= 14);
			}

		// Add the face to the array of faces owned by the file.
		AddFaceL(attrib);

		// Unload the face from the cache; loading a font file should not result in the face remaining in the face cache.
		iContext->DeleteFace(iFileName, face_index);
		}
	}

void CFreeTypeFontFile::CreateFilenameInUTF8L(const TDesC& aFileName, RFs& aFileSession)
	{
	CCnvCharacterSetConverter* converter = CCnvCharacterSetConverter::NewLC();
	if (CCnvCharacterSetConverter::EAvailable !=
		converter->PrepareToConvertToOrFromL(KCharacterSetIdentifierUtf8,aFileSession))
		{
		User::Leave(KErrGeneral);
		}
	const TInt filename_length = aFileName.Length();
	TInt utf8_length = 0;
	for (TInt i = 0; i < filename_length; i++)
		{
		const TText c = aFileName[i];
		if (c < 0x80)
			utf8_length++;
		else if (c < 0x800)
			utf8_length += 2;
		else
			utf8_length += 3; // allow 3 bytes, even for parts of surrogate pairs, in case CHARCONV doesn't handle them
		}
	iFileName = new(ELeave) TText8[utf8_length + 1];
	TPtr8 q(iFileName, filename_length * 4);
	converter->ConvertFromUnicode(q, aFileName);
	iFileName[q.Length()] = 0;
	CleanupStack::PopAndDestroy(converter);
	}

#ifndef WORDS_BIGENDIAN
static void SwapWords(TUint16* aStart, TInt aCount)
	{
	TUint8* p = (TUint8*)aStart;
	while (aCount-- > 0)
		{
		const TUint8 temp = *p;
		*p = p[1];
		p[1] = temp;
		p += 2;
		}
	}
#endif

/*
Set the typeface names (family name and full name, in English and the local language).
If this is a TrueType or OpenType font get the names from the TrueType name table,
which are loaded by FreeType and stored in the TT_Face structure.
*/
void CFaceListItem::SetFaceNamesL(TOpenFontFaceAttrib& aAttrib) const
	{
	TInt familyNameLen = 0;
	TUint16 name[TOpenFontFaceAttrib::ENameLength];
	const TInt totalLen = GetFamilyAndStyleNames(TOpenFontFaceAttrib::ENameLength, name, familyNameLen);
	const TPtrC family_name(name, familyNameLen);
	const TPtrC full_name(name, totalLen);

	// Set the local and non-local family and full names to these default versions.
	aAttrib.SetFamilyName(family_name);
	aAttrib.SetLocalFamilyName(family_name);
	aAttrib.SetFullName(full_name);
	aAttrib.SetLocalFullName(full_name);

	// If this is a TrueType font, replace the default names with those in the name table if any.
	if (FT_FACE_FLAG_SFNT & iFace->face_flags)
		{
		SetTTFFaceNamesL(aAttrib);
		}
	}

TInt CFaceListItem::GetFamilyAndStyleNames(TInt aDestMaxLen, TUint16* aDest, TInt& aFamilyNameLen) const
	{
	aFamilyNameLen = 0;
	// Put the family name into <name>. Ignore non-ASCII characters
	const TUint8* p = (const TUint8*) iFace->family_name;
	if (p)
		aFamilyNameLen = CopyName(aDestMaxLen, aDest, p);

	TInt totalLen = aFamilyNameLen;
	// Append the style name if any,
	p = (const TUint8*) iFace->style_name;
	if (p && aFamilyNameLen < aDestMaxLen)
		{
		aDest[totalLen++] = ' ';
		totalLen += CopyName(aDestMaxLen - totalLen, aDest + totalLen, p);
		}
	return totalLen;
	}

//@pre:  aSrc != NULL
TInt CFaceListItem::CopyName(TInt aDestMaxLen, TUint16* aDest, const TUint8* aSrc)
	{
	TInt len = 0;
	while (len < aDestMaxLen && *aSrc)
		{
		if (*aSrc <= 127)
			aDest[len++] = *aSrc;
		aSrc++;
		}
	return len;
	}

void CFaceListItem::GetDesiredLocalLanguageAndMask(TUint16& aDesiredLocalLanguage, TUint16& aLocalLanguageMask)
	{
	switch (User::Language())
		{
		case ELangEnglish: aDesiredLocalLanguage = 0x0809; aLocalLanguageMask = 0xFFFF; break;
		case ELangSwissFrench:
		case ELangBelgianFrench:
		case ELangInternationalFrench:
		case ELangFrench: aDesiredLocalLanguage = 0x0C; break;
		case ELangSwissGerman:
		case ELangAustrian:
		case ELangGerman: aDesiredLocalLanguage = 0x07; break;
		case ELangSpanish:  aDesiredLocalLanguage = 0x0A; break;
		case ELangItalian: aDesiredLocalLanguage = 0x10; break;
		case ELangSwedish: aDesiredLocalLanguage = 0x1D; break;
		case ELangDanish: aDesiredLocalLanguage = 0x06; break;
		case ELangNorwegian: aDesiredLocalLanguage = 0x14; break;
		case ELangFinnish: aDesiredLocalLanguage = 0x0B; break;
		case ELangPortuguese: aDesiredLocalLanguage = 0x16; break;
		case ELangTurkish: aDesiredLocalLanguage = 0x1F; break;
		case ELangIcelandic: aDesiredLocalLanguage = 0x0F; break;
		case ELangRussian: aDesiredLocalLanguage = 0x19; break;
		case ELangHungarian: aDesiredLocalLanguage = 0x0E; break;
		case ELangBelgianFlemish:
		case ELangDutch: aDesiredLocalLanguage = 0x13; break;
		case ELangAustralian: aDesiredLocalLanguage = 0x0C09; aLocalLanguageMask = 0xFFFF; break;
		case ELangNewZealand: aDesiredLocalLanguage = 0x1409; aLocalLanguageMask = 0xFFFF; break;
		case ELangCzech: aDesiredLocalLanguage = 0x05; break;
		case ELangSlovak: aDesiredLocalLanguage = 0x1B; break;
		case ELangPolish: aDesiredLocalLanguage = 0x15; break;
		case ELangSlovenian: aDesiredLocalLanguage = 0x24; break;
		case ELangTaiwanChinese: aDesiredLocalLanguage = 0x0104; aLocalLanguageMask = 0xFFFF; break;
		case ELangHongKongChinese: aDesiredLocalLanguage = 0x0304; aLocalLanguageMask = 0xFFFF; break;
		case ELangPrcChinese: aDesiredLocalLanguage = 0x0204; aLocalLanguageMask = 0xFFFF; break;
		case ELangJapanese: aDesiredLocalLanguage = 0x11; break;
		case ELangKorean: aDesiredLocalLanguage = 0x12; break;
		case ELangThai: aDesiredLocalLanguage = 0x1e; break;
		default: break;
		}
	}

void CFaceListItem::SetTTFFaceNamesL(TOpenFontFaceAttrib& aAttrib) const
	{
	// Search for a suitable name record. Always use Windows Unicode encoding.
	const TUint16 desired_platform = 3;	// Windows
	const TUint16 desired_encoding = 1;	// Unicode
	const TUint16 desired_language = 0x0409;
	const TUint16 family_name_id = 1;
	const TUint16 full_name_id = 4;

	TUint16 local_language_mask = 0x00FF; // low byte only - high byte is country or other variant
	TUint16 desired_local_language = 0x09;
	GetDesiredLocalLanguageAndMask(desired_local_language, local_language_mask);

	const TUint name_records = FT_Get_Sfnt_Name_Count(iFace);
	for (TInt i = 0; i < name_records; i++)
		{
		FT_SfntName sfntName;
		if (FT_Get_Sfnt_Name(iFace, i, &sfntName))
			{
			User::Leave(KErrGeneral);
			}
		if (sfntName.platform_id == desired_platform &&
			sfntName.encoding_id == desired_encoding &&
			(sfntName.language_id == desired_language || (sfntName.language_id & local_language_mask) == desired_local_language) &&
			(sfntName.name_id == family_name_id || sfntName.name_id == full_name_id))
			{
			const TUint16* name_start = (TUint16*)sfntName.string;
			const TInt name_length = sfntName.string_len / sizeof(TUint16);
			// Copy the name into a properly aligned buffer.
			TBuf<TOpenFontFaceAttrib::ENameLength> name;
			const TInt truncated_length = Min(name_length,TOpenFontFaceAttrib::ENameLength);
			name.SetLength(truncated_length);
			Mem::Copy((void*)name.Ptr(), name_start, truncated_length * sizeof(TText));
			
#ifndef WORDS_BIGENDIAN
			// Byte-swap the Unicode text.
			SwapWords((TUint16*)name.Ptr(),truncated_length);
#endif

			if (sfntName.language_id == desired_language)
				{
				if (sfntName.name_id == family_name_id)
					{
					aAttrib.SetFamilyName(name);
					}
				else
					{
					aAttrib.SetFullName(name);
					}
				}
			if ((sfntName.language_id & local_language_mask) == desired_local_language)
				{
				if (sfntName.name_id == family_name_id)
					{
					aAttrib.SetLocalFamilyName(name);
					}
				else
					{
					aAttrib.SetLocalFullName(name);
					}
				}
			}
		}
	}

void CFreeTypeFontFile::GetNearestFontInPixelsL(
	RHeap*						aHeap,
	COpenFontSessionCacheList*	aSessionCacheList,
	const TOpenFontSpec&		aDesiredFontSpec,
	TInt						aPixelWidth,
	TInt						aPixelHeight,
	COpenFont*&					aFont,
	TOpenFontSpec&				aActualFontSpec)
	{
	GetNearestFontToDesignHeightInPixelsL(
		aHeap, aSessionCacheList, aDesiredFontSpec, aPixelWidth, aPixelHeight, aFont, aActualFontSpec);
	}

void CFreeTypeFontFile::GetNearestFontToDesignHeightInPixelsL(
	RHeap*						aHeap,
	COpenFontSessionCacheList*	aSessionCacheList,
	const TOpenFontSpec&		aDesiredFontSpec,
	TInt						aPixelWidth,
	TInt						aPixelHeight,
	COpenFont*&					aFont,
	TOpenFontSpec&				aActualFontSpec)
	{
	GetNearestFontInPixelsL(
		aHeap, aSessionCacheList, aDesiredFontSpec, aPixelWidth, aPixelHeight, aFont, aActualFontSpec, 0);
	}

void CFreeTypeFontFile::GetNearestFontToMaxHeightInPixelsL(
	RHeap*						aHeap,
	COpenFontSessionCacheList*	aSessionCacheList,
	const TOpenFontSpec&		aDesiredFontSpec,
	TInt						aPixelWidth,
	TInt						aPixelHeight,
	COpenFont*&					aFont,
	TOpenFontSpec&				aActualFontSpec,
	TInt						aMaxHeight)
	{
	GetNearestFontInPixelsL(
		aHeap, aSessionCacheList, aDesiredFontSpec, aPixelWidth, aPixelHeight, aFont, aActualFontSpec, aMaxHeight);
	}

void CFreeTypeFontFile::GetNearestFontInPixelsL(
	RHeap*						aHeap,
	COpenFontSessionCacheList*	aSessionCacheList,
	const TOpenFontSpec&		aDesiredFontSpec,
	TInt						aPixelWidth,
	TInt						aPixelHeight,
	COpenFont*&					aFont,
	TOpenFontSpec&				aActualFontSpec,
	TInt						aMaxHeight)
/**
Use the standard matcher.
*/
	{
	TInt face_index = 0;
	if (GetNearestFontHelper(aDesiredFontSpec, aPixelWidth, aPixelHeight, face_index, aActualFontSpec))
		{
		// Allow only monochrome and standard anti-aliasing.
		TGlyphBitmapType glyphBitmapType = aDesiredFontSpec.BitmapType();
		if (EAntiAliasedGlyphBitmap != glyphBitmapType)
			{
			glyphBitmapType = EMonochromeGlyphBitmap;
			}
		aFont = CFreeTypeFont::NewL(
			aHeap, aSessionCacheList, this, face_index, aActualFontSpec.Height(),
			aActualFontSpec.WidthFactor(), aActualFontSpec.SlantFactor(),
			glyphBitmapType, aMaxHeight, aActualFontSpec.ScriptTypeForMetrics());
		aActualFontSpec.SetBitmapType(glyphBitmapType);
		if (aMaxHeight)
			{
			aActualFontSpec.SetHeight(aFont->Metrics().Size());
			}
		}
	}

CFreeTypeFont* CFreeTypeFont::NewL(
	RHeap*						aHeap,
	COpenFontSessionCacheList*	aSessionCacheList,
	CFreeTypeFontFile*			aFontFile,
	TInt						aFaceIndex,
	TInt						aSizeInPixels,
	TInt32						aWidthFactor,
	TInt32						aSlantFactor,
	TGlyphBitmapType			aBitmapType,
	TInt						aMaxHeight,
	TInt						aScript)
	{
	CFreeTypeFont* f = (CFreeTypeFont*)aHeap->AllocL(sizeof(CFreeTypeFont));
	new(f) CFreeTypeFont(aHeap, aSessionCacheList, aFontFile, aFaceIndex, aWidthFactor, aSlantFactor, aBitmapType);
	CleanupStack::PushL(f);
	f->ConstructL(aSizeInPixels, aMaxHeight, aScript);
	CleanupStack::Pop();
	return f;
	}

CFreeTypeFont::CFreeTypeFont(RHeap* aHeap, COpenFontSessionCacheList* aSessionCacheList,
							 CFreeTypeFontFile* aFontFile, TInt aFaceIndex,
							 TInt32 aWidthFactor, TInt32 aSlantFactor, TGlyphBitmapType aBitmapType) :
	COpenFont(aHeap, aSessionCacheList, aFontFile, aFaceIndex),
	iWidthFactor(aWidthFactor),
	iSlantFactor(aSlantFactor),
	iBitmapType(aBitmapType)
	{
	}

static TUint TwentySixDotSix2Pixel(TInt32 aInt)
//
// Font units in FreeType are specified in a fixed point notation, which is a
// trick that makes it possible to store a fractional number in an integer variable.
// 26.6 means that the top 26 bits are the integer part, and the bottom 6 bits are
// the fractional part.
//
// 32 (binary 100000) is added to round the fractional part off.
//
	{
	if (0 > aInt)
		aInt = -aInt;
	return (aInt + 32) >> 6;
	}

void CFreeTypeFont::ConstructL(TInt aSizeInPixels, TInt aMaxHeight, TInt aScript)
	{
	CFreeTypeFontFile* file = (CFreeTypeFontFile*)File();
	User::LeaveIfNull( file );
	const CFaceListItem* face = file->LoadFaceL( FaceIndex() );
	TInt unicodeAscender = 0, unicodeDescender = 0;
	face->GetBiggestGlyphsFromSampleL(aScript, unicodeAscender, unicodeDescender);
	if (aMaxHeight)
		{
		aSizeInPixels =
			(unicodeAscender && unicodeDescender) ?
			face->DeriveDesignHeightFromMaxHeightWithGlyphSampleL(
				aMaxHeight, unicodeAscender, unicodeDescender) :
			face->DeriveDesignHeightFromMaxHeightWithBBoxL(aMaxHeight);
		}
	else
		{
		// Have to set the pixel size because no
		// DeriveDesignHeightFromMaxHeightWith...() was called.
		if (FT_Set_Pixel_Sizes(face->Face(), aSizeInPixels, aSizeInPixels))
			User::Leave( KErrGeneral );
		if (aSizeInPixels==0)
			aSizeInPixels=TwentySixDotSix2Pixel(face->Face()->size->metrics.height);
		}
	ComputeMetrics(face->Face(), aSizeInPixels, unicodeAscender, unicodeDescender);
	ComputeMaxWidth(face->Face());
	}

TBool CFaceListItem::LoadGlyphAndGetAscenderDescender(
	TUint32	aCode,
	TInt32&	aAscender,
	TInt32&	aDescender) const
//
//@param aCode Character code
//@param aAscender Vertical distance from the baseline to the topmost point of aCode
//@param aDescender Vertical distance from the baseline to the bottommost point of aCode
//@return ETrue if aCode exists in aFace and can be loaded, otherwise EFalse
//@pre FT_Set_Pixel_Sizes is called
//
	{
	const TUint glyphIndex = FT_Get_Char_Index(iFace, aCode);
	if (!glyphIndex || FT_Load_Glyph(iFace, glyphIndex, FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM))
		return EFalse;
	aAscender  = iFace->glyph->metrics.horiBearingY;
	aDescender = iFace->glyph->metrics.height - iFace->glyph->metrics.horiBearingY;
	// if height < horiBearingY -> no descender possible
	if (0 > aDescender)
		aDescender = 0;
	return ETrue;
	}

void CFaceListItem::GetBiggestGlyphsFromSampleL(
	TInt	aScript,
	TInt&	aUnicodeAscender,
	TInt&	aUnicodeDescender) const
//
//@param aScript The script to determine which glyph sample to use
//@param aUnicodeAscender Unicode of the tallest ascender found in sample
//@param aUnicodeDescender Unicode of the 'deepest' descender found in sample
//
	{
	aUnicodeAscender = aUnicodeDescender = 0;
	const TPtrC glyphSample = GlyphSample::TScript2GlyphSample(aScript);
	if (!glyphSample.Ptr())
		return;
	// Set the face to an arbitrary value assuming the
	// biggest glyphs are the same for different sizes
	if (FT_Set_Pixel_Sizes(iFace, 0, 24))
		User::Leave( KErrGeneral );
	TInt32 maxAscender = 0, maxDescender = 0;
	const TInt totalGlyphsNum = glyphSample.Length();
	for (TInt i = 0; i < totalGlyphsNum; i++)
		{
		TInt32 ascender = 0, descender = 0;
		if (!LoadGlyphAndGetAscenderDescender(*(glyphSample.Ptr() + i), ascender, descender))
			continue;
		// Keep the max up to date
		if (maxAscender < ascender)
			{
			maxAscender = ascender;
			aUnicodeAscender = *(glyphSample.Ptr() + i);
			}
		if (maxDescender < descender)
			{
			maxDescender = descender;
			aUnicodeDescender = *(glyphSample.Ptr() + i);
			}
		}
	}

TInt CFaceListItem::DeriveDesignHeightFromMaxHeightWithGlyphSampleL(
	TInt	aMaxHeightInPixel,
	TInt	aUnicodeAscender,
	TInt	aUnicodeDescender) const
//
//@param aMaxHeightInPixel Maximum height within which the return design height has to fit into
//@param aUnicodeAscender Unicode of ascender with which font height is calculated
//@param aUnicodeDescender Unicode of descender with which font height is calculated
//@return The maximum design height that fits in aMaxHeightInPixel
//@post FT_Set_Pixel_Sizes is called with the return design height
//
	{
	TInt designHeightInPixel = aMaxHeightInPixel;
	do
		{
		if (FT_Set_Pixel_Sizes(iFace, 0, designHeightInPixel))
			User::Leave( KErrGeneral );
		TInt32 ascender = 0, descender = 0, dummyAscender = 0, dummyDescender = 0;
		LoadGlyphAndGetAscenderDescender(aUnicodeAscender,  ascender, dummyDescender);
		LoadGlyphAndGetAscenderDescender(aUnicodeDescender, dummyAscender, descender);
		if (TwentySixDotSix2Pixel(ascender + descender) <= aMaxHeightInPixel)
			{
			break;
			}
		} while (--designHeightInPixel);
	return designHeightInPixel;
	}

TInt CFaceListItem::DeriveDesignHeightFromMaxHeightWithBBoxL(TInt aMaxHeightInPixel) const
//
//@param aMaxHeightInPixel Maximum height within which the return design height has to fit into
//@return The maximum design height with which the bbox would fit in aMaxHeightInPixel
//@post FT_Set_Pixel_Sizes is called with the returned design height
//
	{
	// Calculation is as follows:
	//		boundingBoxHeightInPixel = aMaxHeightInPixel
	//		boundingBoxHeightInFontUnit = iFace->bbox.yMax - iFace->bbox.yMin
	//		PixelsPerFontUnit (PPFU) = boundingBoxHeightInPixel / boundingBoxHeightInFontUnit
	// And also:
	//		PixelsPerEm (PPE) = the design height we are looking for
	//		FontUnitsPerEm (FUPE) = iFace->units_per_EM
	//		PixelsPerFontUnit (PPFU) = PixelsPerEm / FontUnitsPerEm
	// Therefore by combining the equations we get:
	//		boundingBoxHeightInPixel / boundingBoxHeightInFontUnit = PixelsPerEm / FontUnitsPerEm
	// Rearranged:
	//		PixelsPerEm = boundingBoxHeightInPixel * FontUnitsPerEm / boundingBoxHeightInFontUnit
	// Now, if the result of the calculation is integer then that design height will fit
	// but if it is not then we should round down to guarantee the bounding box for the resultant
	// integer design height will fit inside our given maximum height
	//
	const TInt boundingBoxHeightInFontUnit = iFace->bbox.yMax - iFace->bbox.yMin;
	TInt designHeightInPixels = (aMaxHeightInPixel * iFace->units_per_EM) / boundingBoxHeightInFontUnit;
	if (FT_Set_Pixel_Sizes( iFace, designHeightInPixels, designHeightInPixels ))
		User::Leave( KErrGeneral );

	// Unfortunately, this is just the starting point. Actual design heights do not necessarily
	// have a mathematical relationship to font metrics so we need to adjust the design height
	// until we find the best value where the metrics do fit.
	const TInt maxHeightInFontUnit = aMaxHeightInPixel << 6;
	TInt currentMaxHeightInFontUnit = FT_MulFix( boundingBoxHeightInFontUnit, iFace->size->metrics.y_scale );
	while ( currentMaxHeightInFontUnit < maxHeightInFontUnit )
		{
		designHeightInPixels++;
		if (FT_Set_Pixel_Sizes( iFace, designHeightInPixels, designHeightInPixels ))
			User::Leave( KErrGeneral );
		currentMaxHeightInFontUnit = FT_MulFix( boundingBoxHeightInFontUnit, iFace->size->metrics.y_scale );
		}
	while ( currentMaxHeightInFontUnit > maxHeightInFontUnit )
		{
		designHeightInPixels--;
		if (FT_Set_Pixel_Sizes( iFace, designHeightInPixels, designHeightInPixels ))
			User::Leave( KErrGeneral );
		currentMaxHeightInFontUnit = FT_MulFix( boundingBoxHeightInFontUnit, iFace->size->metrics.y_scale );
		}
	return designHeightInPixels;
	}

void CFreeTypeFont::ComputeMetrics(
	const FT_Face&	aFace,
	TInt			aSizeInPixels,
	TInt			aUnicodeAscender,
	TInt			aUnicodeDescender)
//
//@param aFace FreeType face object
//@param aSizeInPixels Design height
//@param aUnicodeAscender Unicode of ascender with which maximum ascent is calculated
//@param aUnicodeDescender Unicode of descender with which maximum descent is calculated
//
// sTypoAscender/sTypoDescender are the only metrics in TrueType/OpenType
// that define in the Basic Latin character set.
// OpenType suggests the corresponding metrics in AFM file should be used.
// Adobe Font Metrics (AFM) File Format Specification in turn suggests that the y-value of the
// top of the lowercase 'd' and the bottom of the lowercase 'p' should be used for sTypoAscender
// and sTypoDescender respectively.
//
// Because there is no guarantee that these table values are accurate, we use them only when
// the characters 'd' and 'p' are absent in the font file.
//
// If aUnicodeAscender or aUnicodeDescender is not given, the 'max' metrics are computed with
// the coordinates of the bbox, which is an imaginary box that encloses _all_ glyphs from the font.
//
	{
	TUint glyphIndex = FT_Get_Char_Index(aFace, 0x0064);
	const TInt32 ascentBasicLatin =
		(glyphIndex && !FT_Load_Glyph(aFace, glyphIndex, FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM)) ?
		aFace->glyph->metrics.horiBearingY :
		FT_MulFix(((TT_Face)aFace)->os2.sTypoAscender, aFace->size->metrics.y_scale);

	glyphIndex = FT_Get_Char_Index(aFace, 0x0070);
	const TInt32 descentBasicLatin =
		(glyphIndex && !FT_Load_Glyph(aFace, glyphIndex, FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM)) ?
		aFace->glyph->metrics.height - aFace->glyph->metrics.horiBearingY :
		FT_MulFix(((TT_Face)aFace)->os2.sTypoDescender, aFace->size->metrics.y_scale);

	const TInt yMaxBBox = FT_MulFix(aFace->bbox.yMax, aFace->size->metrics.y_scale);
	const TInt yMinBBox = FT_MulFix(aFace->bbox.yMin, aFace->size->metrics.y_scale);

	glyphIndex = aUnicodeAscender ? FT_Get_Char_Index(aFace, aUnicodeAscender) : 0;
	const TInt32 ascenderMax =
		(glyphIndex && !FT_Load_Glyph(aFace, glyphIndex, FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM)) ?
		aFace->glyph->metrics.horiBearingY :
		yMaxBBox;

	glyphIndex = aUnicodeDescender ? FT_Get_Char_Index(aFace, aUnicodeDescender) : 0;
	const TInt32 descenderMax =
		(glyphIndex && !FT_Load_Glyph(aFace, glyphIndex, FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM)) ?
		aFace->glyph->metrics.height - aFace->glyph->metrics.horiBearingY :
		yMinBBox;

	iFontCapitalAscent		= TwentySixDotSix2Pixel(ascentBasicLatin);
	iFontStandardDescent	= TwentySixDotSix2Pixel(descentBasicLatin);
	iFontMaxAscent			= TwentySixDotSix2Pixel(ascenderMax);
	iFontMaxDescent			= TwentySixDotSix2Pixel(descenderMax);
	iFontLineGap =
		(FT_FACE_FLAG_SFNT & aFace->face_flags) ?
		iFontMaxAscent + iFontMaxDescent + TwentySixDotSix2Pixel(((TT_Face)aFace)->os2.sTypoLineGap) :
		( ( (iFontMaxAscent + iFontMaxDescent) * 12 ) + 5 ) / 10;
	// old version of metrics left for backward compatibility
	iMetrics.SetSize		(aSizeInPixels);
	iMetrics.SetAscent		(TwentySixDotSix2Pixel(aFace->size->metrics.ascender));
	iMetrics.SetDescent		(TwentySixDotSix2Pixel(aFace->size->metrics.descender));
	iMetrics.SetMaxHeight	(TwentySixDotSix2Pixel(yMaxBBox));
	iMetrics.SetMaxDepth	(TwentySixDotSix2Pixel(yMinBBox));
	}

void CFreeTypeFont::ComputeMaxWidth(const FT_Face& aFace)
//
// Scale the maximum advance by the width factor if it is not unity.
//
	{
	iMetrics.SetMaxWidth(TwentySixDotSix2Pixel(aFace->size->metrics.max_advance));
	if (iWidthFactor && KOneIn16Dot16FixedPointFormat != iWidthFactor)
		{
		TInt32 advance = iMetrics.MaxWidth() << 16;
		advance = FT_MulFix(advance, iWidthFactor);
		iMetrics.SetMaxWidth( advance >> 16 );
		}
	}

// Access to extended API though BC interface
void CFreeTypeFont::ExtendedInterface(TUid aUid, TAny*& aParam)
	{
	if (aUid == KUidOpenFontShapingExtension)
		aParam = static_cast<MOpenFontShapingExtension*>(this);
	else if (aUid == KUidOpenFontTrueTypeExtension)	
		aParam = static_cast<MOpenFontTrueTypeExtension*>(this);
	else
		COpenFont::ExtendedInterface(aUid, aParam);
	}
 
// Rasterize a glyph from unicode value of aCode.
void CFreeTypeFont::RasterizeL(TInt aCode, TOpenFontGlyphData* aGlyphData)
	{
	CFreeTypeFontFile* file = (CFreeTypeFontFile*)File();
	if (!file)
		User::Leave(KErrGeneral);
	file->RasterizeL(
		aCode, FaceIndex(), iMetrics.Size(), iWidthFactor, iSlantFactor, iBitmapType, aGlyphData);
	}

// Rasterize a glyph from glyph code value of aCode.
void CFreeTypeFont::RasterizeGlyphL(TInt aCode,TOpenFontGlyphData* aGlyphData)
	{
	CFreeTypeFontFile* file = (CFreeTypeFontFile*)File();
	if (!file)
		User::Leave(KErrGeneral);
	file->RasterizeGlyphL(
		aCode, FaceIndex(), iMetrics.Size(), iWidthFactor, iSlantFactor, iBitmapType, aGlyphData);
	}

TInt CFreeTypeFont::GlyphIndex(TInt aUnicode) const
	{
	CFreeTypeFontFile* file = static_cast<CFreeTypeFontFile*>(File());
	if (!file)
		return 0;
	return FT_Get_Char_Index(file->LoadFaceL( FaceIndex() )->Face(), aUnicode);
	}

TBool CFreeTypeFont::GlyphPointInHintedPixels(TInt aGlyphIndex, TInt aPointNumber,
	TReal& aX, TReal& aY) const
	{
	CFreeTypeFontFile* file = static_cast<CFreeTypeFontFile*>(File());
	if (!file)
		return EFalse;
	FT_Face face = file->LoadFaceAndSetTransformL( FaceIndex(),
		iMetrics.Size(), iWidthFactor, iSlantFactor )->Face();
	// Load glyph outline, scale and hint but don't rasterize
	if (0 == FT_Load_Glyph(face, aGlyphIndex, FT_LOAD_NO_BITMAP))
		{
		if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE
			|| face->glyph->outline.n_points <= aPointNumber)
			return EFalse;
		FT_Vector& vec = face->glyph->outline.points[aPointNumber];
		// Convert from 1.25.6 fixed point to floating point
		aX = vec.x / 64.0;
		aY = vec.y / 64.0;
		return ETrue;
		}
	return EFalse;
	}
	
TBool CFreeTypeFont::GlyphPointInFontUnits(TInt aGlyphIndex, TInt aPointNumber,
	TInt& aX, TInt& aY) const
	{
	CFreeTypeFontFile* file = static_cast<CFreeTypeFontFile*>(File());
	if (!file)
		return EFalse;
	FT_Face face = file->LoadFaceL( FaceIndex() )->Face();
	// Load glyph outline but don't scale, hint or rasterize
	if (0 == FT_Load_Glyph(face, aGlyphIndex, FT_LOAD_IGNORE_TRANSFORM
		| FT_LOAD_NO_BITMAP | FT_LOAD_NO_SCALE))
		{
		if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE
			|| face->glyph->outline.n_points <= aPointNumber)
			return EFalse;
		FT_Vector& vec = face->glyph->outline.points[aPointNumber];
		aX = vec.x;
		aY = vec.y;
		return ETrue;
		}
	return EFalse;
	}
	
void CFreeTypeFont::GetExtensionFontMetrics(
	MOpenFontShapingExtension::TExtensionFontMetrics& aOut)
	{
	CFreeTypeFontFile* file = static_cast<CFreeTypeFontFile*>(File());
	if (file)
		{
		FT_Face face = file->LoadFaceAndSetTransformL( FaceIndex(),
			iMetrics.Size(), iWidthFactor, iSlantFactor )->Face();
		aOut.iUnitsPerEm = face->units_per_EM;
		aOut.iXPixelsPerEm = face->size->metrics.x_ppem;
		aOut.iYPixelsPerEm = face->size->metrics.y_ppem;
		aOut.iXScaleFactor = face->size->metrics.x_scale / 65536.0;
		aOut.iYScaleFactor = face->size->metrics.y_scale / 65536.0;
		}
	else
		{
		// This shouldn't happen, but we can't panic here.
		aOut.iUnitsPerEm = 1;
		aOut.iXPixelsPerEm = 1.0;
		aOut.iYPixelsPerEm = 1.0;
		aOut.iXScaleFactor = 1.0;
		aOut.iYScaleFactor = 1.0;
		}
	}




TAny* CFreeTypeFont::GetTrueTypeTable(TInt& aError, TUint32 aTag, TInt* aLength)
	{
	CFreeTypeFontFile* file = (CFreeTypeFontFile*)File();
	if (!file)
		{
		aError = KErrNotFound;
		return 0;
		}

	return file->GetTrueTypeTable(aError, FaceIndex(), aTag, aLength);
	}

TInt CFreeTypeFont::ReleaseTrueTypeTable(TAny*)
	{
	// CFreeTypeFontFile keeps hold of tables until destruction
	return KErrNone;
	}

TBool CFreeTypeFont::HasTrueTypeTable(TUint32 aTag)
	{
	FT_ULong table_len = 0;

	CFreeTypeFontFile* file = (CFreeTypeFontFile*)File();
	if ( file == NULL )
		{
		return EFalse;
		}
	
	// locate the table & find the length
	CFaceListItem* faceList = file->LoadFaceL( FaceIndex() );
	FT_Face face = faceList->Face();
	TT_Face ttface = (TT_Face)faceList->Face();
	TInt aError = ttface->goto_table( ttface, aTag, face->stream, &table_len );

	return aError == KErrNone;
	}

void CFreeTypeFontFile::SetGlyphMetrics(FT_GlyphSlot aGlyphSlot,TOpenFontGlyphData* aGlyphData)
	{
	TOpenFontCharMetrics metrics;
	metrics.SetWidth(aGlyphSlot->bitmap.width);
	metrics.SetHeight(aGlyphSlot->bitmap.rows);
	metrics.SetHorizBearingX(aGlyphSlot->bitmap_left);
	metrics.SetHorizBearingY(aGlyphSlot->bitmap_top);
	metrics.SetHorizAdvance(TwentySixDotSix2Pixel(aGlyphSlot->advance.x));
	metrics.SetVertBearingX(0);
	metrics.SetVertBearingY(0);
	metrics.SetVertAdvance(aGlyphSlot->bitmap.rows);
	aGlyphData->SetMetrics(metrics);
	}

void CFreeTypeFontFile::RasterizeL(
	TInt				aCode,
	TInt				aFaceIndex,
	TInt				aSizeInPixels,
	TInt32				aWidthFactor,
	TInt32				aSlantFactor,
	TGlyphBitmapType	aBitmapType,
	TOpenFontGlyphData*	aGlyphData)
	{
	const CFaceListItem* face = LoadFaceAndSetTransformL(aFaceIndex,
		aSizeInPixels, aWidthFactor, aSlantFactor);
	TInt glyphCode = FT_Get_Char_Index(face->Face(), aCode);		
	DoRasterizeGlyphL(glyphCode, face, aBitmapType, aGlyphData);
	}

void CFreeTypeFontFile::RasterizeGlyphL(
	TInt				aCode,
	TInt				aFaceIndex,
	TInt				aSizeInPixels,
	TInt32				aWidthFactor,
	TInt32				aSlantFactor,
	TGlyphBitmapType	aBitmapType,
	TOpenFontGlyphData* aGlyphData)
	{
	const CFaceListItem* face = LoadFaceAndSetTransformL(aFaceIndex,
		aSizeInPixels, aWidthFactor, aSlantFactor);
	DoRasterizeGlyphL(aCode, face, aBitmapType, aGlyphData);
	}

void CFreeTypeFontFile::DoRasterizeGlyphL(
	TInt aCode, const CFaceListItem* aFace,
	TGlyphBitmapType aBitmapType, TOpenFontGlyphData* aGlyphData)
	{
	// Substitute it with Symbian's private use area replacement character
	// if this character is not in the font.  KReplacementCharacter might
	// also be absent in the font - this is valid and FT_Load_Glyph will
	// handle the case when glyph_index is zero.
	//
	const TUint glyph_index =
		(aCode != 0) ? aCode : FT_Get_Char_Index(aFace->Face(), KReplacementCharacter);

	// Set the flag that causes the isFixedPitch flag in the PostScript table to be ignored.
	// If we honour isFoxedPitch, CJK fonts like MSSONG space their Latin characters too widely because all
	// characters are given the width of the widest character in the font. Ignoring the flag does no
	// harm to genuine fixed-width fonts, which will return the same width for all characters.
	//
	const TInt32 load_flags =
		(aBitmapType == EMonochromeGlyphBitmap) ?
		FT_LOAD_RENDER | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_MONOCHROME :
		FT_LOAD_RENDER | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;

	if (FT_Load_Glyph(aFace->Face(), glyph_index, load_flags) != 0)
		User::Leave(KErrGeneral);

	// Translate the glyph data from FreeType to EPOC format.
	SetGlyphMetrics(aFace->Face()->glyph,aGlyphData);
	if (aBitmapType == EMonochromeGlyphBitmap)
		iContext->TranslateMonochromeGlyphBitmap(aFace->Face()->glyph,aGlyphData);
	else
		iContext->TranslateAntiAliasedGlyphBitmap(aFace->Face()->glyph,aGlyphData);
	}

TAny* CFreeTypeFontFile::GetTrueTypeTable(TInt& aError, TInt aFaceIndex,
	TUint32 aTag, TInt* aLength)
	{
	aError = KErrNone;

	// already loaded?
	TPtrC8* table = iTableStore.Find(aTag);
	if (table)
		{
		if (aLength)
			*aLength = table->Length();
		return (TAny*) table->Ptr();
		}

	CFaceListItem* faceList = LoadFaceL( aFaceIndex );
	FT_Face face = faceList->Face();
	TT_Face ttface = (TT_Face)face;

	// locate the table & find the length
	TUint32 length = 0;
	FT_Error fterror = ttface->goto_table(ttface, aTag, face->stream, &length);
	if (fterror != 0)
		{
		aError = KErrNotFound;
		return 0;
		}

	// allocate memory for the table
	unsigned char * buffer = reinterpret_cast<unsigned char *>(
		User::Alloc(length));
	if ( !buffer )
		{
		aError = KErrNoMemory;
		return 0;
		}

	// read the table 
	fterror = FT_Load_Sfnt_Table( face, aTag, 0, buffer, &length );

	if (fterror != 0)
		{
		User::Free(buffer);
		aError = KErrNotFound;
		return 0;
		}

	// store the table
	aError = iTableStore.Insert(aTag, TPtrC8(buffer, length));
	if (aError != KErrNone)
		{
		User::Free(buffer);
		return 0;
		}

	if(aLength)
		*aLength = length;

	return buffer;
	}

void CFreeTypeContext::TranslateMonochromeGlyphBitmap(FT_GlyphSlot aGlyphSlot,TOpenFontGlyphData* aGlyphData)
	{
	const TInt width = aGlyphSlot->bitmap.width;
	const TInt height = aGlyphSlot->bitmap.rows;
	const TInt width_bytes = aGlyphSlot->bitmap.pitch;

	StartGlyph(aGlyphData);
	const TUint8* p = (const TUint8*)aGlyphSlot->bitmap.buffer;
	TInt row = 0;
	while (row < height)
		{
		// Find the number of repeating or non-repeating rows (up to 15)
		TInt count = 1;
		TBool repeating = FALSE;
		const TUint8* cur = p;
		while (count < 15 && row + count < height)
			{
			const TUint8* prev = cur;
			cur += width_bytes;
			const TBool same = Mem::Compare(prev,width_bytes,cur,width_bytes) == 0;
			if (count == 1)
				repeating = same;
			else if (repeating != same)
				break;
			count++;
			}

		// Write a 0 for repeating or a 1 for non-repeating.
		WriteGlyphBit(repeating ? 0 : 1);

		// Write the count.
		WriteGlyphBit(count & 1 ? 1 : 0);
		WriteGlyphBit(count & 2 ? 1 : 0);
		WriteGlyphBit(count & 4 ? 1 : 0);
		WriteGlyphBit(count & 8 ? 1 : 0);

		// Write a single repeating row or all the non-repeating rows.
		const TInt rows_written = repeating ? 1 : count;
		cur = p;
		for (TInt row_written = 0; row_written < rows_written; row_written++, cur += width_bytes)
			{
			TInt col = 0;
			for (TInt byte = 0; byte < width_bytes; byte++)
				{
				unsigned char x = cur[byte];
				for (TInt bit = 0; bit < 8 && col < width; bit++, col++, x <<= 1)
					WriteGlyphBit(x & 128 ? 1 : 0);
				}
			}

		row += count;
		p += width_bytes * count;
		}

	EndGlyph();
	}

void CFreeTypeContext::TranslateAntiAliasedGlyphBitmap(FT_GlyphSlot aGlyphSlot, TOpenFontGlyphData* aGlyphData)
	{
	const TInt width = aGlyphSlot->bitmap.width;
	const TInt height = aGlyphSlot->bitmap.rows;
	const TInt width_bytes = aGlyphSlot->bitmap.pitch;

	StartGlyph(aGlyphData);
	const TUint8* p = (const TUint8*)aGlyphSlot->bitmap.buffer;
	/* 
	Some fonts include embedded bitmaps for certain characters and certain sizes.
	These embedded bitmaps can be 1 bit per pixel.
	*/
	if (aGlyphSlot->bitmap.pixel_mode == ft_pixel_mode_mono)
		{
		// how many whole bytes per line
		const TInt byteCount = width / 8;
		// how many bits used in the last byte - if any.
		const TInt bitCount = width % 8;
		for (TInt row = 0; row < height; row++)
			{
			for (TInt col = 0; col < byteCount; col++)
				{
				WriteMonoData(*p++,8);
				}
			if (bitCount > 0)
				{
				WriteMonoData(*p++,bitCount);
				}
			}
		}
	else	// assume 8 bits per pixel
		{
		TInt row = 0;
		while (row < height)
			{
			const TUint8* q = p;
			for (TInt i = 0; i < width; i++, q++)
				WriteGlyphByte(*q);
			row++;
			p += width_bytes;
			}
		}
	EndGlyph();
	}

void CFreeTypeContext::WriteMonoData(TUint8 aData, TInt aBitCount)
	{
	for (TInt j = 7; j >= 8 - aBitCount; j--)
		{
		WriteGlyphByte((1<<j) & aData ? 255 : 0);
		}
	}

TBool CFreeTypeFontFile::HasUnicodeCharacterL(TInt aFaceIndex, TInt aCode) const
	{
	const CFaceListItem* face = iContext->LoadFaceL(iFileName, aFaceIndex);
	return 0 != FT_Get_Char_Index(face->Face(), aCode);
	}

CFaceListItem::CFaceListItem()
	{
	}

CFaceListItem* CFaceListItem::NewL(CFreeTypeContext* aContext, const TText8* aFileName, TInt aFaceIndex)
	{
	CFaceListItem* item = new(ELeave) CFaceListItem;
	CleanupStack::PushL(item);
	item->ConstructL(aContext, aFileName, aFaceIndex);
	CleanupStack::Pop();
	return item;
	}

void CFaceListItem::ConstructL(CFreeTypeContext* aContext, const TText8* aFileName, TInt aFaceIndex)
	{
	// Open the face and select the Unicode character map.
	iFileName = aFileName;
	iFaceIndex = aFaceIndex;
    TInt error = FT_New_Face(
    	aContext->Library(), (const char *) aFileName, aFaceIndex, &iFace);
	if (!error)
		error = FT_Select_Charmap(iFace, ft_encoding_unicode);
	if (error)
		{
		iFace = NULL;
		User::Leave(KErrGeneral);
		}
	}

CFaceListItem::~CFaceListItem()
	{
	FT_Done_Face(iFace);
	}

FT_Face CFaceListItem::Face() const
	{
	return iFace;
	}

CFaceList::CFaceList()
	{
	}

CFaceList::~CFaceList()
	{
	CFaceListItem* next = NULL;
	for (CFaceListItem* p = iFirstItem; p; p = next)
		{
		next = p->iNext;
		delete p;
		}
	}

CFaceListItem* CFaceList::LoadFaceL(
	CFreeTypeContext*	aContext,
	const TText8*		aFileName,
	TInt				aFaceIndex)
	{
	CFaceListItem* prev = NULL;
	for (CFaceListItem* p = iFirstItem; p; prev = p, p = p->iNext)
		{
		if (p->iFileName == aFileName && p->iFaceIndex == aFaceIndex) // found; move to head of list
			{
			if (prev)
				{
				prev->iNext = p->iNext;
				p->iNext = iFirstItem;
				iFirstItem = p;
				}
			return p;
			}
		}

	// Load and add a new item to the head of the list
	CFaceListItem* new_item = CFaceListItem::NewL(aContext, aFileName, aFaceIndex);
	new_item->iNext = iFirstItem;
	iFirstItem = new_item;


    /*
    If too much memory has been used delete item(s) from the end of the list, but don't
    delete the last item, which is the one requested.
    */
#ifdef _DEBUG   
    TInt DeleteCount = 0;
#endif  
    
    while (iFirstItem->iNext && MemoryUsed() > EMemoryThreshold)
        {
#ifdef _DEBUG
        DeleteCount++;
#endif      
        DeleteLastFace();
        }
    
#ifdef _DEBUG   
    if(DeleteCount) 
        {
        RDebug::Print(_L("Delete %d in Face Cache: MemoryUsed() > EMemoryThreshold"),DeleteCount);
        }
#endif
    
    return iFirstItem;
	}

void CFaceList::DeleteFace(const TText8* aFileName, TInt aFaceIndex)
	{
	CFaceListItem* prev = NULL;
	for (CFaceListItem* p = iFirstItem; p; prev = p, p = p->iNext)
		{
		if (p->iFileName == aFileName && p->iFaceIndex == aFaceIndex) // found; delete it
			{
			if (prev)
				prev->iNext = p->iNext;
			else
				iFirstItem = p->iNext;
			delete p;
			return;
			}
		}
	}

void CFaceList::DeleteLastFace()
	{
	CFaceListItem* p = iFirstItem;
	if (p)
		{
		CFaceListItem* prev = NULL;
		while (p && p->iNext)
			{
			prev = p;
			p = p->iNext;
			}
		if (prev)
			prev->iNext = NULL;
		else
			iFirstItem = NULL;
		delete p;
		}
	}