fontservices/fontstore/src/FNTBODY.CPP
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 18 Aug 2010 11:34:25 +0300
changeset 51 a7c938434754
parent 44 601ab138ba0b
child 49 4d76f1414957
permissions -rw-r--r--
Revision: 201033 Kit: 201033

/*
* Copyright (c) 1996-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 <s32file.h>
#include <fntstore.h>
#include "FNTBODY.H"
#include <graphics/openfontconstants.h>

#include "OstTraceDefinitions.h"
#ifdef OST_TRACE_COMPILER_IN_USE
#include "FNTBODYTraces.h"
#endif


CFontStoreFile::CFontStoreFile()
 :	iCollectionUid(KNullUid),
	iUsageCount(1),
	iFileStore(NULL),
	iFileAddress(0),
	iDataStreamId(KNullStreamId)
	{
	}

void CFontStoreFile::ConstructL(const TParse& aParse,RFs& aFs)
	{
	TInt drive;
	User::LeaveIfError(RFs::CharToDrive(aParse.Drive()[0], drive));
	TDriveInfo driveinfo;
	User::LeaveIfError(aFs.Drive(driveinfo, drive));
	RFile file;

	// store the filename
	iFullName = aParse.FullName().AllocL();
	User::LeaveIfError(file.Open(aFs, *iFullName, EFileStream | EFileRead | EFileShareReadersOnly));

	// check to see if the fonts are stored on ROM.  Note that NAND != rom so font files in NAND devices
	// must be handled as if they were in RAM.  A NULL pointer returned by IsFileInRom means its RAM

	if (aFs.IsFileInRom(*iFullName)!=NULL)
		{
		// fonts are stored on a XIP (execute in place) device
		TInt ret = file.Seek(ESeekAddress, iFileAddress);

		if (ret != KErrNone)
			{
			file.Close();
			User::Leave(ret);
			}
		}

	// convert RFile into a CDirectFileStore
	CDirectFileStore* fileStore = CDirectFileStore::FromLC(file);

	if (fileStore->Type()[1] != TUid::Uid(KFontStoreFileUidVal))
		User::Leave(KErrNotSupported);
	TStreamId headerid = fileStore->Root();
	RStoreReadStream stream;
	stream.OpenLC(*fileStore, headerid);
	TInt fnttranversion = stream.ReadInt32L();
	// This works for version 42 (with new metrics) and for earlier versions 
	// which will synthesize the required metrics. It may have to be changed 
	// if the version number is incremented again.
	if (fnttranversion < (KFnttranVersion - 1)  && fnttranversion != KFnttran7650Version) 
		User::Leave(KErrNotSupported);
	iFontVersion = fnttranversion;
	stream >> iCollectionUid;
	iKPixelAspectRatio = stream.ReadInt32L();
	stream >> iDataStreamId;
	CleanupStack::PopAndDestroy(&stream);	// close root stream
	// ensure font data stream can be opened
	stream.OpenLC(*fileStore, iDataStreamId);
	CleanupStack::PopAndDestroy(&stream);	// close font stream
	// transfer ownership of fileStore
	CleanupStack::Pop(fileStore);
	iFileStore = fileStore;
	}

CFontStoreFile* CFontStoreFile::NewL(const TParse& aParse, RFs& aFs)
	{
	CFontStoreFile* fontstorefile = new(ELeave) CFontStoreFile;
	CleanupStack::PushL(fontstorefile);
	fontstorefile->ConstructL(aParse, aFs);
	CleanupStack::Pop();
	return fontstorefile;
	}

CFontStoreFile::~CFontStoreFile()
	{
	delete iFullName;
	iFullName = NULL;
	delete iFileStore;
	iFileStore = NULL;
	}

TBitmapCodeSection::TBitmapCodeSection()
 :	TCodeSection(),
	iCharacterData(),
	iBitmapData()
	{
	}

//This method is called  from CFontBitmap::InternalizeL.
//We have to read stream IDs from the stream, not offsets.
//Obviously the method is called once per life time of 
//CFontBitmap instance.
void TBitmapCodeSection::InternalizeL(RReadStream &aStream)
	{
	iStart = aStream.ReadUint16L();
	iEnd = aStream.ReadUint16L();
	aStream >> iCharacterData.iOffsetsId;
	aStream >> iBitmapData.iBitmapId; 
	}

//This method is called  from CFontBitmap::RestoreComponentsL - 
//if the CFontBitmap instance is in RAM and CFontBitmap::iComponentsRestored is EFalse.
//We use here stream IDs, not offsets.
//If the memory allocation for the offsets doesn't fail - aAllocMemCounter is incremented
//After calling of TBitmapCodeSection::InternalizeOffsetsL character metrics streamID is no more valid - 
//we have valid character metrics offset into RAM memory.
void TBitmapCodeSection::InternalizeOffsetsL(const CStreamStore& aStreamStore, RHeap* aHeap, TInt& aAllocMemCounter)
	{
	RStoreReadStream stream;
	stream.OpenLC(aStreamStore, iCharacterData.iOffsetsId);

	TInt size = stream.ReadInt32L();
	TBitmapFontCharacterOffset* characterOffsetsList = (TBitmapFontCharacterOffset*)aHeap->AllocL(sizeof(TBitmapFontCharacterOffset) * size);
	aAllocMemCounter++;
	iCharacterData.iCharacterOffsetsListOffset = TInt(characterOffsetsList) - TInt(this);
	TBitmapFontCharacterOffset* pEnd = characterOffsetsList + size;
	for (TBitmapFontCharacterOffset* p = characterOffsetsList; p < pEnd; p++)
		{
		p->InternalizeL(stream);
		}

	CleanupStack::PopAndDestroy();
	}

//This method is called  from CFontBitmap::RestoreComponentsL - 
//if the CFontBitmap instance is in RAM and CFontBitmap::iComponentsRestored is EFalse.
//We use here stream IDs, not offsets.
//If the memory allocation for the bitmap doesn't fail - aAllocMemCounter is incremented
//After calling of TBitmapCodeSection::InternalizeBitmapL bitmap streamID is no more valid - 
//we have valid bitmap offset into RAM memory.
void TBitmapCodeSection::InternalizeBitmapL(const CStreamStore& aStreamStore, RHeap* aHeap, TInt& aAllocMemCounter)
	{
	RStoreReadStream stream;
	stream.OpenLC(aStreamStore, iBitmapData.iBitmapId);

	TInt size = stream.ReadInt32L();
	TUint8* bitmap = (TUint8*)aHeap->AllocL(size);
	aAllocMemCounter++;
	iBitmapData.iBitmapOffset = TInt(bitmap) - TInt(this);
	stream.ReadL(bitmap, size);

	CleanupStack::PopAndDestroy();
	}

//This method is called from CFontBitmap::InternalizeL if the
//CFontBitmap instance is in ROM.
//We use here stream IDs to calculate offsets.
//After calling of TBitmapCodeSection::FixUpComponents streamIDs are no more valid - 
//we have valid offsets into ROM memory.
//Obviously the method is called once per life time of 
//CFontBitmap instance.
void TBitmapCodeSection::FixUpComponents(TInt aFileAddress)
	{
	TBitmapFontCharacterOffset* characterOffsetsList = (TBitmapFontCharacterOffset*) (aFileAddress + sizeof(TInt) + iCharacterData.iOffsetsId);
	iCharacterData.iCharacterOffsetsListOffset = TInt(characterOffsetsList);
	TUint8* bitmap = (TUint8*) (aFileAddress + sizeof(TInt) + iBitmapData.iBitmapId);
	iBitmapData.iBitmapOffset = TInt(bitmap);
	}

//This method is caled from CFontBitmap::DeleteComponents(),
//only if the CFontBitmap instance is in RAM.
void TBitmapCodeSection::DeleteOffsets(RHeap* aHeap)
	{
	TBitmapFontCharacterOffset*  charactersOffsetsList = CharacterOffsetsList(ETrue);
	if(TUint32(this) != TUint32(charactersOffsetsList))
		{
		aHeap->Free(charactersOffsetsList);
		}
	}

//This method is caled from CFontBitmap::DeleteComponents(),
//only if the CFontBitmap instance is in RAM.
void TBitmapCodeSection::DeleteBitmap(RHeap* aHeap)
	{
	TUint8* bitmap = Bitmap(ETrue);
	if(TUint32(this) != TUint32(bitmap))
		{
		aHeap->Free(bitmap);
		}
	}

TBitmapFontCharacterOffset* TBitmapCodeSection::CharacterOffsetsList(TBool aIsInRAM) const
	{
	return reinterpret_cast <TBitmapFontCharacterOffset*> 
		(iCharacterData.iCharacterOffsetsListOffset + (aIsInRAM ? TInt(this) : 0));
	}

TUint8* TBitmapCodeSection::Bitmap(TBool aIsInRAM) const
	{
	return reinterpret_cast <TUint8*> 
		(iBitmapData.iBitmapOffset + (aIsInRAM ? TInt(this) : 0));
	}

TCharacterMetricsTable::TCharacterMetricsTable(RHeap* aHeap)
 :	iHeap(aHeap),
	iMetricsStartId(KNullStreamId),
	iCharacterMetricsStartPtr(0),
	iNumberOfMetrics(0),
	iMetricsOnHeap(EFalse)
	{}

void TCharacterMetricsTable::InternalizeL(RReadStream& aStream)
	{
	iMetricsStartId = aStream.ReadInt32L();
	iNumberOfMetrics = aStream.ReadInt32L();
	}

void TCharacterMetricsTable::InternalizeMetricsL(RReadStream& aStream)
	{
	aStream.ReadInt32L(); // size
	TBitmapFontCharacterMetrics* charactermetricslist = static_cast<TBitmapFontCharacterMetrics*>(iHeap->AllocL(sizeof(TBitmapFontCharacterMetrics) * iNumberOfMetrics));
	iMetricsOnHeap = ETrue;
	// Offset from this to location on the heap ('cos the file is not in ROM)
	iCharacterMetricsStartPtr = reinterpret_cast<TInt>(charactermetricslist) - reinterpret_cast<TInt>(this);
	TBitmapFontCharacterMetrics* pEnd = charactermetricslist + iNumberOfMetrics;
	for (TBitmapFontCharacterMetrics* p = charactermetricslist; p < pEnd; p++)
		{
		p->InternalizeL(aStream);
		}
	}

void TCharacterMetricsTable::RestoreL(const CStreamStore& aStreamStore)
	{
	if (iCharacterMetricsStartPtr == 0)
		{	// We haven't already read it in from RAM file
		RStoreReadStream stream;
		stream.OpenLC(aStreamStore, iMetricsStartId);
		InternalizeMetricsL(stream);
		CleanupStack::PopAndDestroy();
		}
	}

void TCharacterMetricsTable::FixUp(TInt aFileAddress)
	{
	TBitmapFontCharacterMetrics* charactermetricslist = reinterpret_cast<TBitmapFontCharacterMetrics*>(aFileAddress + sizeof(TInt) + iMetricsStartId.Value());
	iCharacterMetricsStartPtr = TInt(charactermetricslist);	// Ptr to location in a ROM file
	iMetricsStartId = KNullStreamId;
	iMetricsOnHeap = EFalse;
	}

void TCharacterMetricsTable::Delete()
	{	// This routine is only called if the font file is in RAM, not ROM, and therefore the metrics have been stashed on the heap
    if (iMetricsOnHeap && iCharacterMetricsStartPtr)
        {
        iHeap->Free(reinterpret_cast<TAny*>(MetricsFromOffset(0)));
        iCharacterMetricsStartPtr = 0;
        iMetricsOnHeap = EFalse;
        }
	}

const TBitmapFontCharacterMetrics* TCharacterMetricsTable::Metric(TInt aIndex) const
	{
	if ((aIndex < 0) || (aIndex > iNumberOfMetrics))
	    {
	    OstTraceExt2( TRACE_FATAL, TCHARACTERMETRICSTABLE_METRIC, "TCharacterMetricsTable::Metric, aIndex=%d, iNumberOfMetrics=%d, Panic(EFntMetricsIndexOutOfBounds)", aIndex, iNumberOfMetrics);
	    __ASSERT_DEBUG(0, Panic(EFntMetricsIndexOutOfBounds));
	    }
    // Sometimes the start ptr is to a metrics heap item and sometimes it points into a ROM file
    if (iMetricsOnHeap)
        {
        // Start ptr is to metrics heap item
        return MetricsFromOffset(aIndex);
        }
    else
        {
        // Start ptr is to a file in ROM
        return reinterpret_cast<const TBitmapFontCharacterMetrics*> (iCharacterMetricsStartPtr + (aIndex * sizeof(TBitmapFontCharacterMetrics)));
        }
	}

TInt TCharacterMetricsTable::NumberOfMetrics() const
	{
	return iNumberOfMetrics;
	}

TBitmapFontCharacterMetrics* TCharacterMetricsTable::MetricsFromOffset(TInt aIndex) const
    {
    __ASSERT_DEBUG(iMetricsOnHeap,Panic(EFntMetricsNotOnHeap));
    return reinterpret_cast<TBitmapFontCharacterMetrics*>(reinterpret_cast<TInt>(this) + iCharacterMetricsStartPtr+ (aIndex * sizeof(TBitmapFontCharacterMetrics)));
    }

CFontBitmap::CFontBitmap(RHeap* aHeap, CFontStoreFile* aFontStoreFile)
 :	iHeap(aHeap),
	iFontStoreFileOffset(0),
	iUid(KNullUid),
	iPosture(0),
	iStrokeWeight(0),
	iIsProportional(0),
	iIsInRAM(!aFontStoreFile->iFileAddress),
	iUsageCount(1),
	iCellHeightInPixels(0),
	iAscentInPixels(0),
	iMaxCharWidthInPixels(0),
	iMaxNormalCharWidthInPixels(0),
	iBitmapEncoding(0),
	iNumCodeSections(0),
	iCodeSectionListOffset(0),
	iCharacterMetricsTable(aHeap),
	iComponentsRestored(EFalse),
	iAllocMemCounter_Offsets(0),
	iAllocMemCounter_Bitmaps(0),
	iFontCapitalAscent(0),
	iFontMaxAscent(0),
	iFontStandardDescent(0),
	iFontMaxDescent(0),
	iFontLineGap(0)
	{
	iFontStoreFileOffset = TInt(aFontStoreFile) - TInt(this);
	}

void CFontBitmap::InternalizeL(RReadStream &aStream, TInt aFontVersion)
	{
	aStream >> iUid;
	iPosture = aStream.ReadInt8L();
	iStrokeWeight = aStream.ReadInt8L();
	iIsProportional = aStream.ReadInt8L();
	iCellHeightInPixels = aStream.ReadInt8L();
	iAscentInPixels = aStream.ReadInt8L();
	iMaxCharWidthInPixels = aStream.ReadInt8L();
	iMaxNormalCharWidthInPixels = aStream.ReadInt8L();
	if ( aFontVersion  >= KFnttranVersion )
		{ // read the new metrics in
		iFontCapitalAscent = aStream.ReadInt8L();
		iFontMaxAscent = aStream.ReadInt8L();
		iFontStandardDescent = aStream.ReadInt8L();
		iFontMaxDescent = aStream.ReadInt8L();
		iFontLineGap = aStream.ReadInt8L();
		}
	else // synthesize the extra metrics (data compatibility with third party bitmap fonts for old phones)
		{
		iFontMaxAscent = iFontCapitalAscent = iAscentInPixels;
		iFontMaxDescent = iFontStandardDescent = iCellHeightInPixels - iAscentInPixels;
		iFontLineGap = ( ( iCellHeightInPixels * 12 ) + 5) / 10;  // 1.2 times design height
		}	
	iBitmapEncoding = aStream.ReadInt32L();
	iCharacterMetricsTable.InternalizeL(aStream);
	const TBool fixup = FontStoreFile()->iFileAddress;
	if (fixup)
		{
		iCharacterMetricsTable.FixUp(FontStoreFile()->iFileAddress);
		}
	iNumCodeSections = aStream.ReadInt32L();
	TBitmapCodeSection* codesectionlist = (TBitmapCodeSection*)User::LeaveIfNull(iHeap->AllocL(iNumCodeSections * sizeof(TBitmapCodeSection)));
	iCodeSectionListOffset = TInt(codesectionlist) - TInt(this);
	for (TInt i = 0; i < iNumCodeSections; i++)
		{
		new(codesectionlist + i) TBitmapCodeSection;
		codesectionlist[i].InternalizeL(aStream);
		if (fixup)
			codesectionlist[i].FixUpComponents(FontStoreFile()->iFileAddress);
		}
	}

void CFontBitmap::UseL()
	{
	// Note object is created with a Usage Count of 1.
	// So incrementing to 2 normally indicates the first external reference.
	iUsageCount++;
	if (iUsageCount == 2)
		{
		RestoreComponentsL();
		}
	}

void CFontBitmap::Release()
	{
	iUsageCount--;
	if (!iUsageCount)
		{ // object and all its users have closed
		delete this;
		}
	}

/*
Get the metrics for a given character.
Return aBytes as null if the character aCode doesn't exist in the font.
*/
TBitmapFontCharacterMetrics CFontBitmap::CharacterMetrics(TInt aCode, const TUint8*& aBytes) const
	{
 	const TBitmapCodeSection* matchSection = NULL;
	const TBitmapCodeSection* const lastSection = CodeSectionList() + iNumCodeSections - 1;

	TBitmapFontCharacterOffset offset;
	aBytes = NULL;

	TBitmapFontCharacterMetrics metrics;
	const TBitmapCodeSection* startSearchBand = CodeSectionList();
	TInt numCodeSectionsRemaining = iNumCodeSections;
	while (numCodeSectionsRemaining >= 1)
		{
		TInt halfNumCodeSectionsRemaining = numCodeSectionsRemaining/2;
		const TBitmapCodeSection* centralSearchBand = startSearchBand+halfNumCodeSectionsRemaining;
		if ((aCode >= centralSearchBand->iStart) && (aCode <= centralSearchBand->iEnd))
			{
			matchSection = centralSearchBand;
			break;
			}
		else if ((aCode < centralSearchBand->iStart) || (centralSearchBand == lastSection))
			numCodeSectionsRemaining = halfNumCodeSectionsRemaining;
		else
			{
			startSearchBand = centralSearchBand + 1;
			numCodeSectionsRemaining -= halfNumCodeSectionsRemaining + 1;
			}
		}

	if (matchSection)
		{
		offset =* ((matchSection->CharacterOffsetsList(iIsInRAM)) + (aCode-matchSection->iStart));

		// Fill characters within code section.
		// Recursive call ensures that a valid metric is always returned.
		if (offset.iBitmapOffset == KFillCharacterOffset)
			{
			return CharacterMetrics(KReplacementCharacter, aBytes);
			}
		
		aBytes = matchSection->Bitmap(iIsInRAM) + offset.iBitmapOffset;
		
		// retrieve metric index from encoded 1 or 2 bytes
		TInt index = 0;
		TUint8 byte1 = (TUint8)*aBytes;
		const TInt switchMask = 0x1;
		const TBool oneByteIndex =! (byte1 & switchMask);
		byte1 = TUint8(byte1 >> 1);
		if (oneByteIndex)
			{
			index = byte1;
			aBytes += 1;
			}
		else
			{
			const TUint8 byte2 = (TUint8)(*(aBytes + 1));
			index = byte1 + (byte2 * 128);
			aBytes += 2;
			}
		// Copy metric from table
		metrics =* iCharacterMetricsTable.Metric(index);
		}
	return metrics;
	}

void CFontBitmap::operator delete(TAny *aThis)
	{
	if (((CFontBitmap *)aThis)->iHeap)
		{
		((CFontBitmap *)aThis)->iHeap->Free(aThis);
		}
	}

void CFontBitmap::SetPosture(TFontPosture aPosture)
	{
	iPosture = (TInt8)aPosture;
	}

TFontPosture CFontBitmap::Posture() const
	{
	return (TFontPosture)iPosture;	 // iPosture is always smaller than TFontPosture
	}

void CFontBitmap::SetStrokeWeight(TFontStrokeWeight aStrokeWeight)
	{
	iStrokeWeight = (TInt8)aStrokeWeight;
	}

TFontStrokeWeight CFontBitmap::StrokeWeight() const
	{
	return (TFontStrokeWeight)iStrokeWeight;
	}

void CFontBitmap::SetIsProportional(TBool aIsProportional)
	{
	iIsProportional = (TInt8)aIsProportional;
	}

TBool CFontBitmap::IsProportional() const
	{
	return iIsProportional;
	}

CFontStoreFile* CFontBitmap::FontStoreFile() const
	{
	TInt fsf = TInt(this) + iFontStoreFileOffset;
	return (CFontStoreFile*)fsf;
	}

CFontBitmap::~CFontBitmap()
	{
	DeleteComponents();
	TBitmapCodeSection* codeSectionList = CodeSectionList();
	if(TUint32(this) != TUint32(codeSectionList))
		{
		iHeap->Free(codeSectionList);
		}
	iCodeSectionListOffset = 0;
	}

//We have to count how many offsets and bitmaps are allocated successfully because if
//some of codesection's Internalize..L fails we have to deallocate the right amount of 
//data.
void CFontBitmap::RestoreComponentsL()
	{
	if (iIsInRAM)
		{
		if(!iComponentsRestored)
			{
			iAllocMemCounter_Offsets = 0;
			iAllocMemCounter_Bitmaps = 0;
			CStreamStore& store =* FontStoreFile()->iFileStore;
			for (TInt i = 0; i < iNumCodeSections; i++)
				{
				CodeSectionList()[i].InternalizeOffsetsL(store, iHeap, iAllocMemCounter_Offsets);
				CodeSectionList()[i].InternalizeBitmapL(store, iHeap, iAllocMemCounter_Bitmaps);
				}
			iCharacterMetricsTable.RestoreL(store);
			}
		iComponentsRestored = ETrue;
		}
	}

void CFontBitmap::DeleteComponents()
	{
	if (iIsInRAM)
		{
		TInt i;
		for (i = 0; i < iAllocMemCounter_Offsets; i++)
			{
			CodeSectionList()[i].DeleteOffsets(iHeap);
			}
		for (i = 0; i < iAllocMemCounter_Bitmaps; i++)
			{
			CodeSectionList()[i].DeleteBitmap(iHeap);
			}
		iCharacterMetricsTable.Delete();
		}
	iAllocMemCounter_Offsets = 0;
	iAllocMemCounter_Bitmaps = 0;
	iComponentsRestored = EFalse;
	}

TBitmapCodeSection* CFontBitmap::CodeSectionList() const
	{
	TInt bcs = TInt(this) + iCodeSectionListOffset;
	return (TBitmapCodeSection*)bcs;
	}

TTypefaceFontBitmap::TTypefaceFontBitmap()
 :	iTypeface(NULL),
	iFontBitmap(NULL),
	iHeightFactor(1),
	iWidthFactor(1)
	{
	}

TTypefaceFontBitmap::TTypefaceFontBitmap(TTypeface* aTypeface,CFontBitmap* aFontBitmap)
 :	iTypeface(aTypeface),
	iFontBitmap(aFontBitmap),
	iHeightFactor(1),
	iWidthFactor(1)
	{
	}

TInt TTypefaceFontBitmap::HeightInPixels() const
	{
	return iFontBitmap->iCellHeightInPixels * iHeightFactor;
	}