--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/fontservices/fontstore/src/OPENFONT.CPP Tue Feb 02 02:02:46 2010 +0200
@@ -0,0 +1,2936 @@
+/*
+* 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);
+ }