diff -r 000000000000 -r 1fb32624e06b fontservices/fontstore/src/FNTSTORE.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fontservices/fontstore/src/FNTSTORE.CPP Tue Feb 02 02:02:46 2010 +0200 @@ -0,0 +1,5219 @@ +/* +* Copyright (c) 1995-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 +#include +#include +#include +#include +#include "FNTBODY.H" +#include "FNTSTD.H" +#include + +#define DO_LOADFONT_OPTIMIZATION 1 +#include +#include "linkedfontsprivate.h" +#include "openfontsprivate.h" +#include +#include +#include +#include +#include + +static const TUint32 KOutlineGlyphIdHashMask = 0x0000ffff; +static const TUint32 KOutlineFileUidHashMask = 0x00ff0000; +static const TUint32 KOutlineFaceIndexHashMask = 0x0f000000; +static const TUint32 KOutlineFontPtrHashMask = 0x0fff0000; + +// uncomment to enable some verbose debug prints +//#define VERBOSE_DEBUG 1 + + +/** These constants set the default pixel width and height, in Twips x1000. + Hal Data information overrides this if it is available. EDisplayXPixels & EDisplayXTwips, + EDisplayYPixels & EDisplayYTwips values are required respectively. + + (11860 is approx equivalent to 120 pixels per inch.) +@internalComponent +*/ +const TInt KDefaultPixelWidthInTwips = 11860; +const TInt KDefaultPixelHeightInTwips = 11860; + +// default granularity for arrays +const TInt KDefaultArrayGranularity = 8; + +/* Maximum height of a character bitmap. When font height in pixel is 1024, each +character bitmap is equal to (roughly) 1024 x 1024 x 8 bits/pixel = 1 MB. +@internalComponent +*/ +const TInt KMaxFontHeightInPixels = 1024; + +/* Minimum height of font in pixels that can be displayed on the screen. +@internalComponent +*/ +const TInt KMinFontHeightInPixels = 2; +/** +The arbitrary list of sizes, in points, returned for scaleable fonts. +We can't return 2^32 - 1 sizes, or something that reflect the fact +that any size is okay, because a UI will probably try to create a listbox containing all the sizes. + +Array stored in Twips as that is the only form of the value currently used. +@internalComponent +*/ +#define POINTSIZE_IN_TWIPS(p) ((p) * 20) +const TInt gOpenFontSizeInTwipsArray[] = + { + // 4pt-18pt in steps of 1pt (15 sizes) + POINTSIZE_IN_TWIPS(4), POINTSIZE_IN_TWIPS(5), POINTSIZE_IN_TWIPS(6), + POINTSIZE_IN_TWIPS(7), POINTSIZE_IN_TWIPS(8), POINTSIZE_IN_TWIPS(9), + POINTSIZE_IN_TWIPS(10), POINTSIZE_IN_TWIPS(11), POINTSIZE_IN_TWIPS(12), + POINTSIZE_IN_TWIPS(13), POINTSIZE_IN_TWIPS(14), POINTSIZE_IN_TWIPS(15), + POINTSIZE_IN_TWIPS(16), POINTSIZE_IN_TWIPS(17), POINTSIZE_IN_TWIPS(18), + // 20pt-36pt in steps of 2pt (9 sizes) + POINTSIZE_IN_TWIPS(20), POINTSIZE_IN_TWIPS(22), POINTSIZE_IN_TWIPS(24), + POINTSIZE_IN_TWIPS(26), POINTSIZE_IN_TWIPS(28), POINTSIZE_IN_TWIPS(30), + POINTSIZE_IN_TWIPS(32), POINTSIZE_IN_TWIPS(34), POINTSIZE_IN_TWIPS(36), + // 40pt-72pt in steps of 4pt (9 sizes) + POINTSIZE_IN_TWIPS(40), POINTSIZE_IN_TWIPS(44), POINTSIZE_IN_TWIPS(48), + POINTSIZE_IN_TWIPS(52), POINTSIZE_IN_TWIPS(56), POINTSIZE_IN_TWIPS(60), + POINTSIZE_IN_TWIPS(64), POINTSIZE_IN_TWIPS(68), POINTSIZE_IN_TWIPS(72), + // 80pt-144pt in steps of 8pt (9 sizes) + POINTSIZE_IN_TWIPS(80), POINTSIZE_IN_TWIPS(88), POINTSIZE_IN_TWIPS(96), + POINTSIZE_IN_TWIPS(104), POINTSIZE_IN_TWIPS(112), POINTSIZE_IN_TWIPS(120), + POINTSIZE_IN_TWIPS(128), POINTSIZE_IN_TWIPS(136), POINTSIZE_IN_TWIPS(144) + }; + +const TInt KOpenFontSizeArrayCount = sizeof(gOpenFontSizeInTwipsArray) / sizeof(gOpenFontSizeInTwipsArray[0]); + +/** +@internalTechnology + The folder used to store linked fonts; the character represents the system drive + location and the descriptor contains the private path of fbserv. + */ +_LIT(KLinkedFontFileFolder, "%c:%Slfonts\\"); + +/** +@internalTechnology + The folder used to store updated linked fonts; the descriptor should be formatted + with the formatted version of KLinkedFontFileFolder. Files will be moved from this + folder to KLinkedFontFileFolder at boot time before the font loading procedure. + */ +_LIT(KLinkedFontFileTempFolder, "update\\"); + +/** +The font search string. The Y: directory prefix forces the search to +start with drive Y:. The drives will be searched in the order Y: to A: then Z: +*/ +_LIT(KFBSERVFontDirSecure, "y:\\resource\\fonts\\"); + +/**The maximum length of the linked font folder path*/ +const TInt KMaxLinkedFontPathLength = 36; + +/**The maximum length of a private path*/ +const TInt KMaxPrivatePathLength = 19; + +/** Container for TTypefaceSupport that describes an Open Font family. + +There is an implicit assumption that all fonts in the family will have the same attributes +as the first instance found. E.g. that the range of font heights is the same. + +An array of pointers to the COpenFontFile file objects that hold fonts in this family +also provides reference counting for the object. + +@internalComponent +*/ +NONSHARABLE_CLASS(CTypefaceSupportInfo) : public CBase + { +public: + CTypefaceSupportInfo(); + inline TInt AddFontFilePtr(COpenFontFile* aOpenFontFile); + inline TInt AddUniqueFontFilePtr(COpenFontFile* aOpenFontFile,const TOpenFontFaceAttrib& aFaceAttrib); + inline TInt FindFontFilePtr(COpenFontFile* aOpenFontFile); + inline TBool RemoveFontFilePtr(TInt aIndex); + void SetTypefaceInfo(const TOpenFontFaceAttrib& aFaceAttrib, TInt aMinHeightInTwips); + inline const TTypefaceSupport* TypefaceSupport() const; + inline TInt NearestPointSizeIndex() const; + static TInt CompareFontNames(const CTypefaceSupportInfo& aTypeface1, const CTypefaceSupportInfo& aTypeface2); + ~CTypefaceSupportInfo(); + +public: + TTypefaceSupport iSupport; + // pointers back to the COpenFontFile object which has one or more typefaces in this family + RPointerArray iOpenFontFilePtrArray; + // nearest standard point size index; + TInt iNearestPointSizeIndex; + }; + + +/** helper class used with the cleanup stack +@internalComponent +*/ +class TCleanupRemoveFontFile + { +public: + inline TCleanupRemoveFontFile(CFontStore* aFontStore, TUid aFontUid); +public: + CFontStore* iFontStore; + TUid iFontUid; + }; + + +// declare static functions +static TInt MatchFontSpecsInPixels(const TOpenFontSpec& aCandidateFontSpec, + const TOpenFontSpec& aIdealFontSpec, TInt aCandidateMaxHeight = 0, TInt aIdealMaxHeight = 0); +static void ReadFromFileL(RFile& aFile, TDes8& aDes, TInt aLength); +static TUint TtfTableTagFromBufferL(TDes8& aDes); + +#ifdef _DEBUG +static TUint32 StartTiming(void); +static TUint32 FinishTimingL(TUint32 startTime); +#endif + +static TBool FileIsOnZ(TParse& aFileName); +static TBool FileIsInList(TParse& aFileName, RArray& aList); + + +/** Helper function for converting a pointer to an offset from the passed +heap base. Use OffsetToPointer() to convert the returned offset back to a +useable pointer. +@param aAny A pointer to be converted to an offset. +@param aHeapBase The heap base of the current process. +@return An offset representing the passed pointer that can be converted +back to a pointer using the function OffsetToPointer(). +@see OffsetToPointer() + */ +LOCAL_C TInt PointerToOffset(const TAny* aAny, TUint8* aHeapBase) + { + if (aAny && aHeapBase) + { + return (TInt)aAny - (TInt)aHeapBase; + } + return 0; + } + +/** Helper function for converting an offset (that was calculated using +PointerToOffset()) back to a pointer relative to the passed heap base. +@param aOffset The offset to be converted to a pointer. +@param aHeapBase The heap base of the current process. +@return A pointer relative to the passed heap base. +@see PointerToOffset() + */ +LOCAL_C TAny* OffsetToPointer(const TInt aOffset, TUint8* aHeapBase) + { + if (aOffset && aHeapBase) + { + return (TAny*)(aOffset + (TInt)aHeapBase); + } + return NULL; + } + +// CTypefaceSupportInfo +CTypefaceSupportInfo::CTypefaceSupportInfo() + { + } + + +CTypefaceSupportInfo::~CTypefaceSupportInfo() + { // no ownership of font files, so just Close the array + iOpenFontFilePtrArray.Close(); + } + + +/** Add a back pointer to an Open Font file, in sorted order. +@param aOpenFontFile font file that has a typeface in this family. +@return KErrNone if added, KErrAlreadyExists if file is already referenced, or KErrNoMemory. +@internalComponent +*/ +TInt CTypefaceSupportInfo::AddFontFilePtr(COpenFontFile* aOpenFontFile) + { + return iOpenFontFilePtrArray.InsertInAddressOrder(aOpenFontFile); + } + +/** Add a back pointer to an Open Font file, in sorted order, but only if the font details are unique. +@param aOpenFontFile font file that has a typeface in this family. +@return KErrNone if added, KErrInUse if another file already defines this, KErrAlreadyExists if file is already referenced, or KErrNoMemory. +@internalComponent +*/ +TInt CTypefaceSupportInfo::AddUniqueFontFilePtr(COpenFontFile* aOpenFontFile,const TOpenFontFaceAttrib& aFaceAttrib) + { +#ifdef _DEBUG + _LIT(KLoadedFont, "TypefaceSupport: already loaded font: %S\n"); +#endif + + TPtrC findName=aFaceAttrib.FullName(); + for (TInt i=0,maxi=iOpenFontFilePtrArray.Count();iFaceCount();jFaceAttrib(j); + TPtrC cmpName=cmpFace.FullName(); + if (cmpName==findName) + { +#ifdef _DEBUG + RDebug::Print(KLoadedFont, &findName); +#endif + return KErrInUse; + } + } + } + } + return iOpenFontFilePtrArray.InsertInAddressOrder(aOpenFontFile); + } + +/** Check font family for back pointer to an Open Font file. +@param aOpenFontFile font file that may have a typeface in this family. +@return KErrNotFound or the index of pointer +@internalComponent +*/ +TInt CTypefaceSupportInfo::FindFontFilePtr(COpenFontFile* aOpenFontFile) + { + return iOpenFontFilePtrArray.FindInAddressOrder(aOpenFontFile); + } + + +/** Remove a font file back pointer. +@param aIndex the index of pointer, from FindFontFilePtr() +@return ETrue if there are no more implementations of the font family +@internalComponent +*/ +TBool CTypefaceSupportInfo::RemoveFontFilePtr(TInt aIndex) + { + iOpenFontFilePtrArray.Remove(aIndex); + return iOpenFontFilePtrArray.Count() == 0; + } + + +/** Set the details of the typeface family. +@param aFaceAttrib typeface to parameterise. +@internalComponent +*/ +void CTypefaceSupportInfo::SetTypefaceInfo(const TOpenFontFaceAttrib& aFaceAttrib, TInt aMinHeightInTwips) + { + iSupport.iTypeface.iName = aFaceAttrib.ShortFamilyName(); + iSupport.iTypeface.SetIsProportional(!aFaceAttrib.IsMonoWidth()); + iSupport.iTypeface.SetIsSerif(aFaceAttrib.IsSerif()); + iSupport.iTypeface.SetIsSymbol(aFaceAttrib.IsSymbol()); + + // Find minimum size in twips then find the next higher standard size. + iSupport.iMinHeightInTwips = aMinHeightInTwips; + TInt fontSizeIndex = 0; + for (; fontSizeIndex < KOpenFontSizeArrayCount; ++fontSizeIndex) + { + const TInt KMinHeightInTwips = gOpenFontSizeInTwipsArray[fontSizeIndex]; + if (aMinHeightInTwips <= KMinHeightInTwips) + { + aMinHeightInTwips = KMinHeightInTwips; + break; + } + } + iNearestPointSizeIndex = fontSizeIndex; + iSupport.iMaxHeightInTwips = Max(gOpenFontSizeInTwipsArray[KOpenFontSizeArrayCount - 1], iSupport.iMinHeightInTwips); + iSupport.iNumHeights = Max(1,KOpenFontSizeArrayCount - iNearestPointSizeIndex); + iSupport.iIsScalable = TRUE; + } + + +/** Get the details of the typeface family. +@internalComponent +*/ +const TTypefaceSupport* CTypefaceSupportInfo::TypefaceSupport() const + { + return &iSupport; + } + +/** Get the Nearest Standard Point Size Index. +@internalComponent +*/ +TInt CTypefaceSupportInfo::NearestPointSizeIndex() const + { + return iNearestPointSizeIndex; + } + +// for InsertInOrder +TInt CTypefaceSupportInfo::CompareFontNames(const CTypefaceSupportInfo& aTypeface1, const CTypefaceSupportInfo& aTypeface2) + { + return aTypeface1.iSupport.iTypeface.iName.CompareF(aTypeface2.iSupport.iTypeface.iName); + } + + +// TCleanupRemoveFontFile +TCleanupRemoveFontFile::TCleanupRemoveFontFile(CFontStore* aFontStore, TUid aFontUid) : + iFontStore(aFontStore), iFontUid(aFontUid) + { + } + + +TBitmapFontCharacterOffset::TBitmapFontCharacterOffset() + : iBitmapOffset(0) + {} + +void TBitmapFontCharacterOffset::InternalizeL(RReadStream& aStream) + { + iBitmapOffset = aStream.ReadUint16L(); + }; + +EXPORT_C TCharacterMetrics::TCharacterMetrics() + : iAscentInPixels(0), + iHeightInPixels(0), + iLeftAdjustInPixels(0), + iMoveInPixels(0), + iRightAdjustInPixels(0) + { + } + +TBitmapFontCharacterMetrics::TBitmapFontCharacterMetrics() + : iAscentInPixels(0), + iHeightInPixels(0), + iLeftAdjustInPixels(0), + iMoveInPixels(0), + iRightAdjustInPixels(0) + { + } + +void TBitmapFontCharacterMetrics::InternalizeL(RReadStream& aStream) + { + iAscentInPixels = aStream.ReadInt8L(); + iHeightInPixels = aStream.ReadInt8L(); + iLeftAdjustInPixels = aStream.ReadInt8L(); + iMoveInPixels = aStream.ReadInt8L(); + iRightAdjustInPixels = aStream.ReadInt8L(); + } + +/** Constructor. */ +EXPORT_C TAlgStyle::TAlgStyle() + : iBaselineOffsetInPixels(0), + iFlags(0), + iWidthFactor(1), + iHeightFactor(1) + { + } + +/** Sets whether the font is bold. + +@param aIsBold ETrue if the font is bold; otherwise EFalse. */ +EXPORT_C void TAlgStyle::SetIsBold(TBool aIsBold) + { + if (aIsBold) + iFlags |= EBold; + else + iFlags &= ~EBold; + } + +/** Sets whether the font is italic. + +@param aIsItalic ETrue if the font is italic; otherwise EFalse. */ +EXPORT_C void TAlgStyle::SetIsItalic(TBool aIsItalic) + { + if (aIsItalic) + iFlags |= EItalic; + else + iFlags &= ~EItalic; + } + +/** Sets whether the font is mono width - i.e. all characters have the same width. + +@param aIsMono ETrue if the font is mono width; otherwise EFalse. */ +EXPORT_C void TAlgStyle::SetIsMono(TBool aIsMono) + { + if (aIsMono) + iFlags|=EMono; + else + iFlags&=~EMono; + } + +/** Sets the width factor. + +@param aWidthFactor A width factor. */ +EXPORT_C void TAlgStyle::SetWidthFactor(TInt aWidthFactor) + { + iWidthFactor=(TInt8) aWidthFactor; + } + +/** Sets the height factor. + +@param aHeightFactor A height factor. */ +EXPORT_C void TAlgStyle::SetHeightFactor(TInt aHeightFactor) + { + iHeightFactor=(TInt8) aHeightFactor; + } + +/** Returns whether the font is bold. + +@return ETrue if the font is bold; otherwise EFalse. */ +EXPORT_C TBool TAlgStyle::IsBold() const + { + return iFlags&EBold; + } + +/** Returns whether the font is italic. + +@return ETrue if the font is italic; otherwise EFalse. */ +EXPORT_C TBool TAlgStyle::IsItalic() const + { + return iFlags&EItalic; + } + +/** Returns whether the font is mono - i.e. all characters have the same width. + +@return ETrue if the font is mono; otherwise EFalse. */ +EXPORT_C TBool TAlgStyle::IsMono() const + { + return iFlags&EMono; + } + +/** Returns the width factor. + +@return A width factor. */ +EXPORT_C TInt TAlgStyle::WidthFactor() const + { + return iWidthFactor; + } + +/** Returns the height factor. + +@return A height factor. */ +EXPORT_C TInt TAlgStyle::HeightFactor() const + { + return iHeightFactor; + } + +EXPORT_C TBool TAlgStyle::operator==(const TAlgStyle& aAlgStyle) const + { + return (iFlags==aAlgStyle.iFlags) && + (iWidthFactor==aAlgStyle.iWidthFactor) && + (iHeightFactor==aAlgStyle.iHeightFactor) && + (iBaselineOffsetInPixels==aAlgStyle.iBaselineOffsetInPixels); + } + +/** +@internalTechnology +*/ +TBool TAlgStyle::operator!=(const TAlgStyle& aAlgStyle) const + { + return !this->operator==(aAlgStyle); + } + +CBitmapFont::CBitmapFont( + RHeap* aHeap, + const TFontSpec& aFontSpecInTwips, + const TAlgStyle& aAlgStyle, + CFontBitmap* aFontBitmap): + iFontSpecInTwips(aFontSpecInTwips), + iAlgStyle(aAlgStyle), + iHeap(aHeap) + { + iFontBitmapOffset = (TInt) ((TUint)(aFontBitmap) - (TUint)(this)); + } + +CBitmapFont::CBitmapFont( + RHeap* aHeap, + const TFontSpec& aFontSpecInTwips, + const TAlgStyle& aAlgStyle, + COpenFont* aOpenFont): + iFontSpecInTwips(aFontSpecInTwips), + iAlgStyle(aAlgStyle), + iHeap(aHeap), + iOpenFont(aOpenFont) + { +#ifdef FNTSTORE_SUPPORT_FMM + iOpenFontOffset=reinterpret_cast(aOpenFont)-reinterpret_cast(this); +#endif // FNTSTORE_SUPPORT_FMM + } + +/** This member is private and not intended for use. */ +void CBitmapFont::ConstructL() + { +#ifdef FNTSTORE_SUPPORT_FMM + if (!IsOpenFont()) + FontBitmap()->UseL(); +#else + if (!iOpenFont) + FontBitmap()->UseL(); +#endif // FNTSTORE_SUPPORT_FMM + } + +/** This member is private and not intended for use. */ +CBitmapFont::~CBitmapFont() + { +#ifdef FNTSTORE_SUPPORT_FMM + if (!IsOpenFont() && iFontBitmapOffset) + FontBitmap()->Release(); + else if (IsOpenFont()) + delete OpenFont(); +#else + if (!iOpenFont) + FontBitmap()->Release(); + delete iOpenFont; +#endif // FNTSTORE_SUPPORT_FMM + } + +CBitmapFont* CBitmapFont::NewL( + RHeap* aHeap, + const TFontSpec& aFontSpecInTwips, + const TAlgStyle& aAlgStyle, + CFontBitmap* aFontBitmap) + { + // font is placed in shared heap + CBitmapFont* f = (CBitmapFont*) aHeap->AllocL(sizeof(CBitmapFont)); + new(f) CBitmapFont(aHeap, aFontSpecInTwips, aAlgStyle, aFontBitmap); + CleanupStack::PushL(f); + f->ConstructL(); + CleanupStack::Pop(f); + return f; + } + +CBitmapFont* CBitmapFont::NewL( + RHeap* aHeap, + const TFontSpec& aFontSpecInTwips, + const TAlgStyle& aAlgStyle, + COpenFont* aOpenFont) + { + // font is placed in shared heap + CBitmapFont* f = (CBitmapFont*) aHeap->AllocL(sizeof(CBitmapFont)); + new(f) CBitmapFont(aHeap,aFontSpecInTwips,aAlgStyle,aOpenFont); + return f; + } + +/** Returns the font type identifier:KCBitmapFontUidVal. + +@return The font type identifier. */ +EXPORT_C TUid CBitmapFont::DoTypeUid() const + { + return TUid::Uid(KCBitmapFontUidVal); + } + +/** Returns a font identifier. + +If it uses an open font the UID returned has a value of zero. Otherwise it +has the UID value of the CFontBitmap it uses. + +@return A font identifier. */ +TUid CBitmapFont::Uid() const + { +#ifdef FNTSTORE_SUPPORT_FMM + if (IsOpenFont()) + return TUid::Uid(0); +#else + if (iOpenFont) + return TUid::Uid(0); +#endif // FNTSTORE_SUPPORT_FMM + else + return FontBitmap()->iUid; + } + +/** Returns the font height in pixels. +For an open font this will be the design height (notional rather than exact). + +@return Font height in pixels. +@see FontMaxHeight() +*/ +EXPORT_C TInt CBitmapFont::DoHeightInPixels() const + { +#ifdef FNTSTORE_SUPPORT_FMM + if (IsOpenFont()) + return Height(OpenFont()->Metrics().Size()); +#else + if (iOpenFont) + return Height(iOpenFont->Metrics().Size()); +#endif // FNTSTORE_SUPPORT_FMM + else + return Height(FontBitmap()->iCellHeightInPixels); + } + +/** Returns the font ascent in pixels. + +The ascent is usually the height of a Latin capital letter above the baseline. +For an open font, the returned value is likely to be inaccurate. +Don't rely on it to get exact metrics at the pixel level. + +@return Font ascent in pixels. +@see FontCapitalAscent() +@see FontMaxAscent() +*/ +EXPORT_C TInt CBitmapFont::DoAscentInPixels() const + { +#ifdef FNTSTORE_SUPPORT_FMM + if (IsOpenFont()) + return Height(OpenFont()->Metrics().Ascent()); +#else + if (iOpenFont) + return Height(iOpenFont->Metrics().Ascent()); +#endif // FNTSTORE_SUPPORT_FMM + else + return Height(FontBitmap()->iAscentInPixels); + } + +/** Returns the width, in pixels, of the given character. + +If all characters have the same width (i.e. the font is mono - an attribute +stored in iAlgStyle) then this is the maximum normal width, returned using +MaxNormalCharWidthInPixels(). + +Note: For OpenType fonts this function returns the horizontal advance of +the character, which may be different from the actual width. + +@param aChar A character. +@return The character width in pixels. */ +EXPORT_C TInt CBitmapFont::DoCharWidthInPixels(TChar aChar) const + { + const TUint8* bytes; + if (iAlgStyle.IsMono()) + return MaxNormalCharWidthInPixels(); + else + return Width(CharacterMetrics(aChar,bytes).iMoveInPixels); + } + +/** Returns the width, in pixels, of the given text. + +@param aText Text string. +@return Width of the text in pixels. */ +EXPORT_C TInt CBitmapFont::DoTextWidthInPixels(const TDesC &aText) const + { + TMeasureTextInput* dummy = NULL; + return DoTextWidthInPixels(aText, dummy); + } + +/** Returns the width, in pixels, of the given text. + +@param aText Text string. +@return Width of the text in pixels. */ +TInt CBitmapFont::DoTextWidthInPixels(const TDesC &aText, const TMeasureTextInput* aParam) const + { + TMeasureTextOutput output; + TInt advance_width = MeasureText(aText,aParam,&output); + return Max(advance_width,output.iBounds.Width()); + } + + +/** Returns the baseline offset in pixels, as stored in iAlgStyle. + +@return The baseline offset in pixels. */ +EXPORT_C TInt CBitmapFont::DoBaselineOffsetInPixels() const + { + return iAlgStyle.iBaselineOffsetInPixels; + } + +/** Returns the number of whole characters of aText, starting from the beginning, +that fit into the given pixel width. + +@param aText A text string. +@param aWidthInPixels A width in pixels. +@return The number of whole characters of aText that fit into aWidthInPixels. +*/ +EXPORT_C TInt CBitmapFont::DoTextCount(const TDesC &aText,TInt aWidthInPixels) const + { + TInt count = 0; + const TInt length = aText.Length(); + TInt width = 0; + // accumulate text width character by character, until target is reached or exceeded + TInt widthDiff = aWidthInPixels - width; + while ( (widthDiff > 0) && (length > count) ) + { + width += TextWidthInPixels(aText.Mid(count,1)); + widthDiff = aWidthInPixels - width; + if (widthDiff >= 0) + { // width <= aWidthInPixels + ++count; + } + } + return count; + } + +/** Returns the number of whole characters of aText, starting from the beginning, +that fit into the given pixel width, and gets the excess width. + +@param aText A text descriptor. +@param aWidthInPixels A width in pixels. +@param aExcessWidthInPixels On return, the width left over of aWidthInPixels +after the maximum possible whole number of characters of aText have been fit +into it. +@return The number of whole characters of aText that fit into aWidthInPixels. */ +EXPORT_C TInt CBitmapFont::DoTextCount(const TDesC &aText,TInt aWidthInPixels,TInt &aExcessWidthInPixels) const + { + TInt count = TextCount(aText,aWidthInPixels); + aExcessWidthInPixels = aWidthInPixels - TextWidthInPixels(aText.Left(count)); + return count; + } + +/** Returns the font's maximum character width in pixels. + +@return The maximum character width in pixels. */ +EXPORT_C TInt CBitmapFont::DoMaxCharWidthInPixels() const + { +#ifdef FNTSTORE_SUPPORT_FMM + if (IsOpenFont()) + return Width(OpenFont()->Metrics().MaxWidth()); +#else + if (iOpenFont) + return Width(iOpenFont->Metrics().MaxWidth()); +#endif // FNTSTORE_SUPPORT_FMM + else + return Width(FontBitmap()->iMaxCharWidthInPixels); + } + +/** Returns the font's normal maximum character width in pixels. + +Note that when a CFontBitmap is used this value is the same as the maximum +character width in pixels returned by MaxCharWidthInPixels(), but when a COpenFont +is used the value may be different. + +@return The normal maximum character width in pixels. */ +EXPORT_C TInt CBitmapFont::DoMaxNormalCharWidthInPixels() const + { +#ifdef FNTSTORE_SUPPORT_FMM + if (IsOpenFont()) + return Width(OpenFont()->Metrics().MaxWidth()); +#else + if (iOpenFont) + return Width(iOpenFont->Metrics().MaxWidth()); +#endif // FNTSTORE_SUPPORT_FMM + else + return Width(FontBitmap()->iMaxNormalCharWidthInPixels); + } + +/** Returns the device-independent font specification for the font. + +Note that this is set when the bitmap font object is constructed. + +@return A font specification. */ +EXPORT_C TFontSpec CBitmapFont::DoFontSpecInTwips() const + { + return iFontSpecInTwips; + } + + +/** Attempts to rasterize a character (aCode) into a data area (aGlyphData) in +shared memory. + +This works only for open fonts: where the bitmap font object is using a COpenFont. + +Bitmap fonts are deemed to be fully rasterized after they have been loaded +from file. + +Returns ETrue if the character was successfully rasterized or was already +in the cache. This function can be called only by the server; rasterization +uses memory and other resources (e.g., file handles) owned by the server. + +@param aSessionHandle A session handle for the open font system. +@param aCode A character code. +@param aGlyphData A data area in shared memory. +@return ETrue if the character was successfully rasterized or was already in +the cache; otherwise EFalse. */ +EXPORT_C TBool CBitmapFont::Rasterize(TInt aSessionHandle, TInt aCode, TOpenFontGlyphData* aGlyphData) const + { +#ifdef FNTSTORE_SUPPORT_FMM + if (IsOpenFont()) + return OpenFont()->Rasterize(aSessionHandle, aCode, aGlyphData); +#else + if (iOpenFont) + return iOpenFont->Rasterize(aSessionHandle, aCode, aGlyphData); +#endif // FNTSTORE_SUPPORT_FMM + else + return EFalse; + } + +/** Gets a pointer to a bitmap and the metrics for a specified character, but only +if a CFontBitmap is being used by the bitmap font object. + +This function does not work when a COpenFont is being used, but GetCharacterData() +can be used instead. + +If the specified character does not exist in the font then the bitmap pointer +and character metrics are gotten for a replacement character, KReplacementCharacter. + +@param aCode A character code. +@param aBytes On return, a pointer to the bitmap for the specified character. +@return Metrics for the specified character. */ +EXPORT_C TCharacterMetrics CBitmapFont::CharacterMetrics(TInt aCode,const TUint8*& aBytes) const + { + /* + This function does not work for Open Fonts because the character data need not be + shared between sessions and a session handle is needed; GetCharacterData should be used instead. + */ +#ifdef FNTSTORE_SUPPORT_FMM + if (IsOpenFont()) +#else + if (iOpenFont) +#endif // FNTSTORE_SUPPORT_FMM + { + aBytes = NULL; + return TCharacterMetrics(); + } + + TBitmapFontCharacterMetrics bitmap_font_metrics = FontBitmap()->CharacterMetrics(aCode,aBytes); + + // Substitute the replacement character if this character doesn't exist in the font. + if (aBytes == NULL) + bitmap_font_metrics = FontBitmap()->CharacterMetrics(KReplacementCharacter,aBytes); + + TCharacterMetrics metrics; + metrics.iAscentInPixels = bitmap_font_metrics.iAscentInPixels; + metrics.iHeightInPixels = bitmap_font_metrics.iHeightInPixels; + metrics.iLeftAdjustInPixels = bitmap_font_metrics.iLeftAdjustInPixels; + metrics.iMoveInPixels = bitmap_font_metrics.iMoveInPixels; + metrics.iRightAdjustInPixels = bitmap_font_metrics.iRightAdjustInPixels; + + if (iAlgStyle.IsMono()) + { + TInt width = metrics.iMoveInPixels - metrics.iLeftAdjustInPixels - metrics.iRightAdjustInPixels; + metrics.iMoveInPixels = FontBitmap()->iMaxNormalCharWidthInPixels; + metrics.iLeftAdjustInPixels = (TInt16)((metrics.iMoveInPixels - width) / 2); + metrics.iRightAdjustInPixels = (TInt16)(metrics.iMoveInPixels - width - metrics.iLeftAdjustInPixels); + } + + return metrics; // N.B. Not doubled for double height and double width. + } + + +/** Gets a pointer to a bitmap and the metrics for a specified character. + +Note that this function calls CharacterMetrics() if a CFontBitmap is being +used by the bitmap font object, and maps the TCharacterMetrics values returned +by that function to aMetrics. + +If the function fails to get the bitmap and metric values (because the character +is in an open font and has not yet been rasterized) returns EFalse. + +@param aSessionHandle A session handle for the open font system. +@param aCode A character code. +@param aMetrics On return, metrics for the specified character. +@param aBitmap On return, a pointer to the bitmap for the specified character. +@return ETrue if successful, otherwise EFalse. */ +EXPORT_C TBool CBitmapFont::GetCharacterData(TInt aSessionHandle,TInt aCode, + TOpenFontCharMetrics& aMetrics,const TUint8*& aBitmap) const + { +#ifdef FNTSTORE_SUPPORT_FMM + if (IsOpenFont()) +#else + if (iOpenFont) +#endif // FNTSTORE_SUPPORT_FMM + { + const TOpenFontCharMetrics* nm; +#ifdef FNTSTORE_SUPPORT_FMM + if (OpenFont()->GetCharacterData(aSessionHandle,aCode,nm,aBitmap)) +#else + if (iOpenFont->GetCharacterData(aSessionHandle,aCode,nm,aBitmap)) +#endif // FNTSTORE_SUPPORT_FMM + { + aMetrics = *nm; + return ETrue; + } + else + return EFalse; + } + else + { + TCharacterMetrics m = CharacterMetrics(aCode,aBitmap); + aMetrics = TOpenFontCharMetrics(m); + return ETrue; + } + } + +/** Gets the open font metrics. + +These metrics distinguish between maximum character height and depth and typographic +ascent and descent, so that the clipping rectangle for text can be distinguished +from the distance to neighbouring baselines. + +@param aMetrics Open font metrics. */ + +EXPORT_C void CBitmapFont::GetFontMetrics(TOpenFontMetrics& aMetrics) const + { +#ifdef FNTSTORE_SUPPORT_FMM + if (IsOpenFont()) + aMetrics = OpenFont()->Metrics(); +#else + if (iOpenFont) + aMetrics = iOpenFont->Metrics(); +#endif // FNTSTORE_SUPPORT_FMM + else + { + new(&aMetrics) TOpenFontMetrics; + aMetrics.SetSize(CBitmapFont::DoHeightInPixels()); + aMetrics.SetAscent(CBitmapFont::DoAscentInPixels()); + aMetrics.SetDescent(aMetrics.Size() - aMetrics.Ascent()); + aMetrics.SetMaxHeight(aMetrics.Ascent()); + aMetrics.SetMaxDepth(aMetrics.Descent()); + aMetrics.SetMaxWidth(CBitmapFont::DoMaxCharWidthInPixels()); + } + } + + +/** Gets the open font typeface attributes if possible. + +At present no attempt is made to sythesize these attributes for bitmap fonts +(CFontBitmaps). + +@param aAttrib On return, the open font typeface attributes. +@return ETrue if successful; EFalse if not possible to get the open font typeface +attributes. */ +EXPORT_C TBool CBitmapFont::GetFaceAttrib(TOpenFontFaceAttrib& aAttrib) const + { +#ifdef FNTSTORE_SUPPORT_FMM + if (IsOpenFont()) +#else + if (iOpenFont) +#endif // FNTSTORE_SUPPORT_FMM + { +#ifdef FNTSTORE_SUPPORT_FMM + const TOpenFontFaceAttrib* a = OpenFont()->FaceAttrib(); +#else + const TOpenFontFaceAttrib* a = iOpenFont->FaceAttrib(); +#endif // FNTSTORE_SUPPORT_FMM + if (a) + { + aAttrib = *a; + return ETrue; + } + } + return EFalse; + } + +/** Gets encoding if a bitmap font (a CFontBitmap) is used. + +@return Bitmap encoding value. */ +EXPORT_C TInt CBitmapFont::BitmapEncoding() const + { +#ifdef FNTSTORE_SUPPORT_FMM + if (IsOpenFont()) + return 0; +#else + if (iOpenFont) + return 0; +#endif // FNTSTORE_SUPPORT_FMM + else + return FontBitmap()->iBitmapEncoding; + } + +/** Gets whether the open or bitmap font has the specified character. + +@param aCode A character code. +@return ETrue if the font has the specified character; otherwise EFalse. */ +EXPORT_C TBool CBitmapFont::HasCharacterL(TInt aCode) const + { +#ifdef FNTSTORE_SUPPORT_FMM + if (IsOpenFont()) + return OpenFont()->HasCharacterL(aCode); +#else + if (iOpenFont) + return iOpenFont->HasCharacterL(aCode); +#endif // FNTSTORE_SUPPORT_FMM + else + { + const TUint8* bytes; + FontBitmap()->CharacterMetrics(aCode,bytes); + return (bytes != NULL); + } + } + +/** Gets whether the specified character needs to be rasterised. + +False is returned if it is a bitmap font (a CFontBitmap) being used by the +bitmap font object (so no rasterization is required) or if is an open font +(a COpenFont) and the character has been rasterized. + +@param aSessionHandle A session handle for the open font system. +@param aCode A character code. +@return ETrue if the character needs to be rasterized; otherwise EFalse. */ +EXPORT_C TBool CBitmapFont::CharacterNeedsToBeRasterized(TInt aSessionHandle,TInt aCode) const + { +#ifdef FNTSTORE_SUPPORT_FMM + if (IsOpenFont()) + return OpenFont()->CharacterNeedsToBeRasterized(aSessionHandle,aCode); +#else + if (iOpenFont) + return iOpenFont->CharacterNeedsToBeRasterized(aSessionHandle,aCode); +#endif // FNTSTORE_SUPPORT_FMM + else + return FALSE; // characters in bitmap fonts do not need to be rasterized + } + +/** Turns text into glyph codes and positions. +@param aText The Unicode text to shape plus context +@return The output shape header from the per-font cache, or 0 on failure. +@internalTechnology +*/ +EXPORT_C TShapeHeader* CBitmapFont::ShapeTextL(const TDesC16& aText, + TInt aSessionHandle, const TShapeMessageParameters& aParams) + { + TShapeHeader* shape = 0; + + if(IsOpenFont()) + { + // get the data in a CShaper::TInput for the shaper + CShaper::TInput input; + input.iText = &aText; + input.iStart = aParams.iStart; + input.iEnd = aParams.iEnd; + input.iScript= aParams.iScript; + input.iLanguage = aParams.iLanguage; + input.iMaximumAdvance = KMaxTInt; + input.iFlags = 0; + input.iSessionHandle = aSessionHandle; + input.iReserved1 = 0; + + TFontShapeFunctionParameters params; + params.iEnd = input.iEnd; + params.iLanguage = input.iLanguage; + params.iScript = input.iScript; + params.iStart = input.iStart; + params.iText = input.iText; + + COpenFont* openFont = OpenFont(); + + //if already exist just increase the reference count for that session + shape = openFont->GetShapedData(aSessionHandle,¶ms); + + if (shape == NULL) + { + if (!openFont->HasShaper() + || (openFont->HasShaper() && ( + (TUint32)(openFont->GetShaper()->ExtendedInterface(KUidShaperGetScript)) != input.iScript + || (TUint32)(openFont->GetShaper()->ExtendedInterface(KUidShaperGetLang)) != input.iLanguage))) + { // Install the shaper + openFont->DeleteShaper(); + InstallOpenFontShaper(openFont, input); + } + + if (openFont->HasShaper()) + { + TInt error = openFont->GetShaper()->ShapeText(shape, input, iHeap); + if (error != KErrNone) + User::Leave(error); + + // Put this into the session cache + TShapeHeader* cached_header = openFont->InsertShapedDataIntoCache(aSessionHandle,¶ms, shape); + if (!cached_header) + User::LeaveNoMemory(); + iHeap->Free(shape); + shape = cached_header; + } + } + } + return shape; + } + + +void CBitmapFont::InstallOpenFontShaper(COpenFont* aOpenFont, CShaper::TInput& aShaperInput) + { + CShaper* shaper = NULL; + const CArrayPtrFlat* shaperFactoryList = aOpenFont->File()->GetFontStore()->ShaperFactoryList(); + + TInt factoryCount = shaperFactoryList->Count(); + for (TInt index = 0; index < factoryCount; index++) + { + TRAPD(err, shaper = (*shaperFactoryList)[index]->NewShaperL(this, + aShaperInput.iScript, aShaperInput.iLanguage, iHeap)); + if (err == KErrNone) + { + aOpenFont->SetShaper(shaper); + break; + } + } + } + + +/** Frees the memory taken up as a result of shaping +@internalTechnology */ +EXPORT_C void CBitmapFont::DeleteShape(TInt aSessionHandle,TShapeHeader* aHeader) + { + //safe to assume aHeader is never NULL? + if (IsOpenFont()) + { + //we just need to decrease the reference count, no deletion here + //as the entry in cache can still be reused by other client + //only in the case where the memory is full, the freeing will + //delete any cache entry that is not referenced at all + TInt ret=OpenFont()->DecrementCachedRefCount(aSessionHandle,aHeader); + //panic in debug mode if trying to delete something that is not there. + __ASSERT_DEBUG(ret==KErrNone || ret==KErrNotFound, User::Invariant()); + } + } + +EXPORT_C void CBitmapFont::operator delete(TAny *aThis) + { + if (((CBitmapFont *)aThis)->iHeap) + ((CBitmapFont *)aThis)->iHeap->Free(aThis); + } + +TInt CBitmapFont::Width(TInt aNum) const + { + TInt widthfactor=iAlgStyle.WidthFactor(); + return ((widthfactor==1)? aNum: aNum*widthfactor); + } + +TInt CBitmapFont::Height(TInt aNum) const + { + TInt heightfactor=iAlgStyle.HeightFactor(); + return ((heightfactor==1)? aNum: aNum*heightfactor); + } + +CFontBitmap* CBitmapFont::FontBitmap() const +/** This member is private and not intended for use. */ + { +#ifdef FNTSTORE_SUPPORT_FMM + __ASSERT_ALWAYS(!IsOpenFont(),Panic(EFntTypefaceHasNoFontBitmaps)); + if(iFontBitmapOffset) + return reinterpret_cast(reinterpret_cast(this)+iFontBitmapOffset); + else + return NULL; +#else + __ASSERT_ALWAYS(!iOpenFont,Panic(EFntTypefaceHasNoFontBitmaps)); + TInt fontbitmap=TInt(this)+iFontBitmapOffset; + return((CFontBitmap*)fontbitmap); +#endif // FNTSTORE_SUPPORT_FMM + } + +/** Gets a font table. +@param aTag: Input. The name of the font table. +@param aTableContent: Output. To return the address of the table content. +@param aLength: Output. To return the length (in bytes) of the table. +@param aSessionHandle: Input. A handle to the session requesting this table. +@return KErrNone on success, specific error code on failure. +@internalTechnology +*/ +EXPORT_C +TInt CBitmapFont::GetFontTable(TUint32 aTag, TAny *&aTableContent, + TInt &aLength, TInt aSessionHandle) + { + COpenFont *fontPtr = NULL; +#ifdef FNTSTORE_SUPPORT_FMM + if (IsOpenFont()) + fontPtr = OpenFont(); +#else + if (iOpenFont) + fontPtr = iOpenFont; +#endif // FNTSTORE_SUPPORT_FMM + else + return KErrNotSupported; + + // try to find it in cache. + CFontStore *fntStore = fontPtr->File()->GetFontStore(); + TUid fileUid = fontPtr->File()->Uid(); + TInt ret = fntStore->FindFontTableInCache(fileUid, aTag, aTableContent, aLength); + if (KErrNone == ret) + { + ret = fntStore->IncFontTableRefCount(fileUid, aTag, aSessionHandle); + return ret; + } + + // font table not found in cache. + ret = fontPtr->GetFontTable(aTag, aTableContent, aLength); + if (KErrNone == ret) + { + ret = fntStore->CacheFontTable(fileUid, aTag, aTableContent, aLength); + if (KErrNone == ret) + { + ret = fntStore->IncFontTableRefCount(fileUid, aTag, aSessionHandle); + } + else + { + aTableContent = NULL; + } + } + + return ret; + } + +/** Release a font table. Decrement its reference count. Remove from cache if + * reference decreases to zero. +@param aTag: Input. The name of the font table to be released. +@param aSessionHandle: Input. Handle to the session releasing this table. +@return KErrNone on success, specific error code on failure. +@internalTechnology +*/ +EXPORT_C void CBitmapFont::ReleaseFontTable(TUint32 aTag, + TInt aSessionHandle) + { + COpenFont *fontPtr = NULL; +#ifdef FNTSTORE_SUPPORT_FMM + if (IsOpenFont()) + fontPtr = OpenFont(); +#else + if (iOpenFont) + fontPtr = iOpenFont; +#endif // FNTSTORE_SUPPORT_FMM + else + return; + + CFontStore *fntStore = fontPtr->File()->GetFontStore(); + TUid fileUid = fontPtr->File()->Uid(); + fntStore->ReleaseFontTable(fileUid, aTag, aSessionHandle); + } + + +/** Release a number of glyph outlines. Decrement their reference count. + * Remove it from cache if reference count decreases to zero. +@param aCount: Input. Number of outlines to be released. +@param aCodes: Input. An array of codes. Its interpretation depends on the parameter + 'aIsGlyphId' (see below). +@param aIsGlyphId: Input. When aIsGlyphId==ETrue, 'aCodes' is an array of glyph ID's. + When aIsGlyphId==EFalse, 'aCodes' is an array of Unicode values. +@param aHinted: Input. To indicate if the outlines are hinted or unhinted. +@param aSessionHandle: Input. Handle to the session releasing the outlines. +@return KErrNone on success, specific error code on failure. +@internalTechnology +*/ +EXPORT_C void CBitmapFont::ReleaseGlyphOutlines(TInt aCount, const TUint *aCodes, + TBool aHinted, TInt aSessionHandle) + { + COpenFont *fontPtr = NULL; + #ifdef FNTSTORE_SUPPORT_FMM + if (IsOpenFont()) + fontPtr = OpenFont(); + #else + if (iOpenFont) + fontPtr = iOpenFont; + #endif // FNTSTORE_SUPPORT_FMM + else + return; + + CFontStore *fontStore = fontPtr->File()->GetFontStore(); + + for (TInt i = 0; i < aCount; ++i) + { + if (aHinted) + { + THintedOutlineId outlineId(fontPtr, aCodes[i]); + fontStore->ReleaseHintedOutline(outlineId, aSessionHandle); + } + else + { + TInt faceId = fontPtr->FaceIndex(); + TUnhintedOutlineId outlineId(fontPtr->File()->Uid(), faceId, aCodes[i]); + fontStore->ReleaseUnhintedOutline(outlineId, aSessionHandle); + } + } + } + +/** Gets a font table. +@param aCode: Input. An glyph code. Its interpretation depends on the parameter + 'aIsGlyphId' (see below). +@param aIsGlyphId: Input. When aIsGlyphId==ETrue, 'aCode' is a glyph ID. + When aIsGlyphId==EFalse, 'aCode' is a Unicode values. +@param aHinted: Input. To indicate if hinted or unhinted outline is needed. +@param aOutline: Output. A 'void*' pointer, pointing to the outline in memory. +@param aLength: Output. A TInt, recording the lenght (in bytes) of the outline. +@param aSessionHandle: Input. Handle to the session requesting this outline. +@return KErrNone on success, specific error code on failure. +@internalTechnology +*/ +EXPORT_C TInt CBitmapFont::GetGlyphOutline(TUint aCode, + TBool aHinted, TAny *&aOutline, TInt &aLength, TInt aSessionHandle) + { + COpenFont *fontPtr = NULL; + #ifdef FNTSTORE_SUPPORT_FMM + if (IsOpenFont()) + fontPtr = OpenFont(); + #else + if (iOpenFont) + fontPtr = iOpenFont; + #endif // FNTSTORE_SUPPORT_FMM + else + return KErrNotSupported; + + CFontStore *fontStore = fontPtr->File()->GetFontStore(); + TAny *outlineData = NULL; + TInt len = KErrGeneral; + TInt ret = KErrNone; + if (!aHinted) + { + TInt faceId = fontPtr->FaceIndex(); + TUnhintedOutlineId outlineId(fontPtr->File()->Uid(), faceId, aCode); + ret = fontStore->FindUnhintedOutlineInCache(outlineId, outlineData, len); + if (KErrNotFound == ret) + { + TAny* tmpOutline = 0; + TInt tmpLen = 0; + ret = fontPtr->GetGlyphOutline(aCode, aHinted, tmpOutline, tmpLen); + if (KErrNone == ret) + { + fontStore->CacheUnhintedOutline(outlineId, + tmpOutline, (TInt)tmpLen, outlineData, len); + } + User::Free(tmpOutline); + } + if (KErrNone == ret) + { + fontStore->IncreaseUnhintedOutlineRefCount(outlineId, aSessionHandle); + } + } + else + { + THintedOutlineId outlineId(fontPtr, aCode); + ret = fontStore->FindHintedOutlineInCache(outlineId, outlineData, len); + if (KErrNotFound == ret) + { + TAny* tmpOutline = 0; + TInt tmpLen = 0; + ret = fontPtr->GetGlyphOutline(aCode, aHinted, tmpOutline, tmpLen); + if (KErrNone == ret) + { + fontStore->CacheHintedOutline(outlineId, + tmpOutline, (TInt)tmpLen, outlineData, len); + } + User::Free(tmpOutline); + } + if (KErrNone == ret) + { + fontStore->IncreaseHintedOutlineRefCount(outlineId, aSessionHandle); + } + } + + aOutline = outlineData; + aLength = len; + return KErrNone; + } + +EXPORT_C TUint32 CBitmapFont::UniqueFontId() + { + return iUniqueFontId; + } + +void CBitmapFont::SetUniqueFontId(TUint32 aUniqueFontId) + { + iUniqueFontId = aUniqueFontId; + } + +/** API extension system that enables the caller to access a particular API +extension function. As an overload of this function in a derived class +it calls its immediate parent implementation for any extension function Uid +that it does not recognize and handle. +@param aInterfaceId UID of the required extension function +@param aParam Pointer to an arbitrary parameter block that can be used to +provide and/or return information to/from the particular extension function, +defaults to NULL. +@return Integer return value from extension function +@internalTechnology +@released +*/ +EXPORT_C TInt CBitmapFont::DoExtendedFunction(TUid aFunctionId, TAny* aParam) const + { + if (KFontCapitalAscent == aFunctionId) + { + return Height(IsOpenFont() ? OpenFont()->FontCapitalAscent() : FontBitmap()->FontCapitalAscent()); + } + else if (KFontMaxAscent == aFunctionId) + { + return Height(IsOpenFont() ? OpenFont()->FontMaxAscent() : FontBitmap()->FontMaxAscent()); + } + else if (KFontStandardDescent == aFunctionId) + { + return Height(IsOpenFont() ? OpenFont()->FontStandardDescent() : FontBitmap()->FontStandardDescent()); + } + else if (KFontMaxDescent == aFunctionId) + { + return Height(IsOpenFont() ? OpenFont()->FontMaxDescent() : FontBitmap()->FontMaxDescent()); + } + else if (KFontLineGap == aFunctionId) + { + return Height(IsOpenFont() ? OpenFont()->FontLineGap() : FontBitmap()->FontLineGap()); + } + + return CFont::DoExtendedFunction(aFunctionId, aParam); + } + + +CFontTableCacheItem::CFontTableCacheItem(TUid &aFileUid, const TUint32 aTag, + TInt aOffset, TInt aLength): iFileUid(aFileUid), iTag(aTag), + iOffset(aOffset), iLength(aLength) + { + // a null constructor + } + +CFontTableCacheItem::~CFontTableCacheItem() + { + iUsers.ResetAndDestroy(); + iUsers.Close(); + } + +TBool CFontTableCacheItem::HasOutstandingRefCount() + { + TInt count = iUsers.Count(); + for (TInt j = 0; j < count; ++j) + { + if (iUsers[j]->iRefCount > 0) + { + return ETrue; + } + } + return EFalse; + } + + +TInt CFontTableCacheItem::FindUser(TInt aSessionHandle, TInt *id) + { + TInt len = iUsers.Count(); + for (TInt i = 0; i < len; ++i) + { + if (aSessionHandle == iUsers[i]->iSessionHandle) + { + *id = i; + return KErrNone; + } + } + return KErrNotFound; + } + +TInt CFontTableCacheItem::DecRefCount(TInt aSessionHandle) + { + TInt id = 0; + TInt ret = FindUser(aSessionHandle, &id); + if (KErrNone == ret) + { + iUsers[id]->iRefCount--; + if (0 == iUsers[id]->iRefCount) + { + delete iUsers[id]; + iUsers.Remove(id); + } + return iUsers.Count(); + } + return KErrNotFound; + } + +TInt CFontTableCacheItem::IncRefCount(TInt aSessionHandle) + { + TInt id = 0; + TInt ret = FindUser(aSessionHandle, &id); + if (KErrNone == ret) + { + iUsers[id]->iRefCount++; + } + else + { + TCacheUserInfo *newUser = new TCacheUserInfo(aSessionHandle, 1); + if (NULL != newUser) + { + TRAP(ret, iUsers.AppendL(newUser)); + } + else + { + ret = KErrNoMemory; + } + //coverity[leaked_storage] + // The 'newUser' is kept in iUsers. It will be deleted in DecRefCount(). + } + return ret; + } + +TInt CFontTableCache::Append(TUid aFileUid, TUint32 aTag, + TAny *&aContent, TInt aLength) + { + TInt ret = 0; + if ((TUint32)iCacheMemMon.GetMemUsage() >= KFontTable_GlyphOutline_CacheMaxMem) + { + RDebug::Printf("Table/Glyph cache full. Unable to add new item."); + return KErrNoMemory; + } + // make a copy of the table content on the shared heap. + TAny *sharedCopy = iHeap->Alloc(aLength); + if (NULL == sharedCopy) + { + return KErrNoMemory; + } + + Mem::Copy(sharedCopy, aContent, aLength); + + CFontTableCacheItem *newItem = NULL; + TInt offset = PointerToOffset(sharedCopy, iHeap->Base()); + TRAP(ret, newItem = new(ELeave) CFontTableCacheItem(aFileUid, aTag, offset, aLength)); + if (KErrNone != ret) + { + iHeap->Free(sharedCopy); + return ret; + } + + TRAP(ret, iCacheItems.AppendL(newItem)); + if (KErrNone == ret) + { + // do not free 'aContent', because the mem is managed by + // rasterizer cache. + aContent = sharedCopy; + iCacheMemMon.Inc(aLength); + } + else + { + iHeap->Free(sharedCopy); + } +#ifdef _DEBUG + GetCacheState(__func__); +#endif + return ret; + } + +TInt CFontTableCache::Find(TUid aFileUid, TUint32 aTag, TAny *&aContent, + TInt &aLength, TInt *id) + { + *id = KErrNotFound; + TInt len = iCacheItems.Count(); + + TInt ret = KErrNotFound; + for (TInt i = 0; i < len; ++i) + { + CFontTableCacheItem *item = iCacheItems[i]; + if (item->iFileUid == aFileUid && item->iTag == aTag) + { + aContent = OffsetToPointer(item->iOffset, iHeap->Base()); + aLength = item->iLength; + *id = i; + ret = KErrNone; + break; + } + } + +#ifdef _DEBUG + GetCacheState(__func__); +#endif + return ret; + } + +CFontTableCache::CFontTableCache(RHeap *aHeap, TFontTableGlyphOutlineCacheMemMonitor &aMon): + iCacheMemMon(aMon), iHeap(aHeap) + { + // null constructor + } + +CFontTableCache::~CFontTableCache() + { + for (TInt i = 0; i < iCacheItems.Count(); ++i) + { + iHeap->Free(OffsetToPointer(iCacheItems[i]->iOffset, iHeap->Base())); + } + iCacheItems.ResetAndDestroy(); + iCacheItems.Close(); + } + +TInt CFontTableCache::IncRefCount(TUid aFileUid, TUint32 aTag, TInt aSessionHandle) + { + TAny *outline = NULL; + TInt len = 0; + TInt id = 0; + + TInt ret = Find(aFileUid, aTag, outline, len, &id); + if (KErrNone == ret) + { + ret = iCacheItems[id]->IncRefCount(aSessionHandle); + } + +#ifdef _DEBUG + GetCacheState(__func__); +#endif + return ret; + } + +TInt CFontTableCache::DecRefCount(TUid aFileUid, TUint32 aTag, TInt aSessionHandle) + { + TAny *outline = NULL; + TInt len = 0; + TInt id = 0; + + TInt ret = Find(aFileUid, aTag, outline, len, &id); + if (KErrNone == ret) + { + TInt numUsers = iCacheItems[id]->DecRefCount(aSessionHandle); + if (0 == numUsers) + { + // There is no outstanding reference to the cache item. + iHeap->Free(outline); + iCacheMemMon.Dec(len); + delete (iCacheItems[id]); + iCacheItems.Remove(id); + } + } + +#ifdef _DEBUG + GetCacheState(__func__); +#endif + return ret; + } + +TBool CFontTableCache::HasOutstandingRefCount() + { + TInt len = iCacheItems.Count(); + + for (TInt i = 0; i < len; ++i) + { + if (iCacheItems[i]->HasOutstandingRefCount()) + { + return ETrue; + } + } + return EFalse; + } + +TBool CFontTableCache::HasOutstandingRefCountWithUid(TUid aFileUid) + { + TInt len = iCacheItems.Count(); + + for (TInt i = 0; i < len; ++i) + { + if (iCacheItems[i]->iFileUid == aFileUid) + { + if (iCacheItems[i]->HasOutstandingRefCount()) + { + return ETrue; + } + } + } + return EFalse; + } + +void CFontTableCache::CleanupCacheOnOpenFontFileRemoval(COpenFontFile *) + { + // In CFontStore::RemoveFile(), a font file is not allowed to be removed if + // there are outstanding ref counts on any table in it. If that check passed + // and this function is called, there shall be no cache item for that file. + + // Currently a cache item having a refcount of 0 is removed immediately. + // If this strategy is changed in the future, we may need to do some + // cleanup here. + } + +void CFontTableCache::CleanupCacheOnFbsSessionTermination(TInt aSessionHandle) + { + TInt len = iCacheItems.Count(); + + for (TInt i = 0; i < len; ++i) + { + TInt id = -1; + if (KErrNone == iCacheItems[i]->FindUser(aSessionHandle, &id)) + { + iCacheItems[i]->iUsers.Remove(id); + if (iCacheItems[i]->iUsers.Count() == 0) + { + iHeap->Free(OffsetToPointer(iCacheItems[i]->iOffset, iHeap->Base())); + iCacheMemMon.Dec(iCacheItems[i]->iLength); + delete iCacheItems[i]; + iCacheItems.Remove(i); + } + } + } + } + + +#ifdef _DEBUG +TInt CFontTableCache::GetCacheState(const char *func) + { + RDebug::Printf("%s called from %s: ", __func__, func); + TBuf<256> buf; + + int len = iCacheItems.Count(); + int numTables = 0, numSessions = 0, totalRef = 0; + buf.Append(_L("Table cache: ")); + for (int i = 0; i < len; ++i) + { + ++numTables; + TInt abc = iCacheItems[i]->iUsers.Count(); + numSessions += abc; + for (int j = 0; j < abc; ++j) + { + totalRef += iCacheItems[i]->iUsers[j]->iRefCount; + } + } + if (0 == iCacheItems.Count()) + { + buf.Append(_L("cache empty. ")); + } + else + { + buf.AppendFormat(_L("%d tables referenced by %d sessions, total ref count %d"), + numTables, numSessions, totalRef); + } + RDebug::RawPrint(buf); + return 0; + } +#endif + + + +TInt COutlineCacheItem::FindUser(TInt aSessionHandle, TInt *id) + { + TInt len = iUsers.Count(); + for (TInt i = 0; i < len; ++i) + { + if (aSessionHandle == iUsers[i]->iSessionHandle) + { + *id = i; + return KErrNone; + } + } + return KErrNotFound; + } + +COutlineCacheItem::~COutlineCacheItem() + { + iUsers.ResetAndDestroy(); + } + +COutlineCacheItem::COutlineCacheItem(TInt aOffset, TInt aLength): + iOffset(aOffset), iLength(aLength) + { + // a null constructor. + } + +TInt COutlineCacheItem::DecRefCount(TInt aSessionHandle) + { + TInt id = 0; + TInt ret = FindUser(aSessionHandle, &id); + if (KErrNone == ret) + { + iUsers[id]->iRefCount--; + if (0 == iUsers[id]->iRefCount) + { + delete iUsers[id]; + iUsers.Remove(id); + } + return iUsers.Count(); + } + return KErrNotFound; + } + +TInt COutlineCacheItem::IncRefCount(TInt aSessionHandle) + { + TInt id = 0; + TInt ret = FindUser(aSessionHandle, &id); + if (KErrNone == ret) + { + iUsers[id]->iRefCount++; + } + else + { + TCacheUserInfo *newUser = new TCacheUserInfo(aSessionHandle, 1); + if (NULL != newUser) + { + TRAP(ret, iUsers.AppendL(newUser)); + } + else + { + ret = KErrNoMemory; + } + //coverity[leaked_storage] + // The 'newUser' is kept in iUsers. It will be deleted in DecRefCount(). + } + return ret; + } + +#ifdef _DEBUG +TInt CUnhintedOutlineCache::GetCacheState(const char *func) + { + RDebug::Printf("%s called from %s: ", __func__, func); + int numSessions = 0, totalRef = 0; + THashMapIter it(iItemIdMap); + it.NextValue(); + while (it.CurrentValue()) + { + COutlineCacheItem **data = it.CurrentValue(); + int len = (*data)->iUsers.Count(); + numSessions += len; + for (int j = 0; j < len; ++j) + { + totalRef += (*data)->iUsers[j]->iRefCount; + } + it.NextValue(); + } + + TBuf<256> buf; + buf.Append(_L("Unhinted outline cache: ")); + TInt numItems = iItemIdMap.Count(); + if (0 == numItems) + { + buf.Append(_L("empty. ")); + } + else + { + buf.AppendFormat(_L("%d glyphs, %d sessions, total refcount %d"), + numItems, numSessions, totalRef); + } + + RDebug::RawPrint(buf); + + return 0; + } +#endif + +CUnhintedOutlineCache::CUnhintedOutlineCache(RHeap *aHeap, TFontTableGlyphOutlineCacheMemMonitor &aMon): + iCacheMemMon(aMon), iHeap(aHeap), + iItemIdMap(THashFunction32(CUnhintedOutlineCache::IdHash), + TIdentityRelation(CUnhintedOutlineCache::IdIdentity)) + { + + } + +CUnhintedOutlineCache::~CUnhintedOutlineCache() + { + THashMapIter it(iItemIdMap); + it.NextValue(); + while (it.CurrentValue()) + { + const TUnhintedOutlineId *outlineId = it.CurrentKey(); + COutlineCacheItem **data = it.CurrentValue(); + + // loop body here! + iHeap->Free(OffsetToPointer((*data)->iOffset, iHeap->Base())); + delete (*data); + iItemIdMap.Remove(*outlineId); + // end loop body + + it.NextValue(); + } + return; + } + + +TInt CUnhintedOutlineCache::CleanupCacheOnOpenFontFileRemoval(COpenFontFile *aFontFile) + { + TUid fileUid = aFontFile->Uid(); + + THashMapIter it(iItemIdMap); + it.NextValue(); + while (it.CurrentValue()) + { + const TUnhintedOutlineId *outlineId = it.CurrentKey(); + COutlineCacheItem **data = it.CurrentValue(); + + // loop body here! + if (outlineId->iFileUid == fileUid) + { + iHeap->Free(OffsetToPointer((*data)->iOffset, iHeap->Base())); + iCacheMemMon.Dec((*data)->iLength); + delete (*data); + iItemIdMap.Remove(*outlineId); + } + // end loop body + + it.NextValue(); + } + return KErrNone; + } + +TInt CUnhintedOutlineCache::CleanupCacheOnFbsSessionTermination(TInt aSessionHandle) + { + THashMapIter it(iItemIdMap); + it.NextValue(); + while (it.CurrentValue()) + { + const TUnhintedOutlineId *outlineId = it.CurrentKey(); + COutlineCacheItem **data = it.CurrentValue(); + + // loop body here! + TInt id = 0; + TInt ret = (*data)->FindUser(aSessionHandle, &id); + if (KErrNone == ret) + { + delete (*data)->iUsers[id]; + (*data)->iUsers.Remove(id); + if (0 == (*data)->iUsers.Count()) + { + iHeap->Free(OffsetToPointer((*data)->iOffset, iHeap->Base())); + iCacheMemMon.Dec((*data)->iLength); + delete (*data); + iItemIdMap.Remove(*outlineId); + } + } + // end loop body + + it.NextValue(); + } + return KErrNone; + } + + +TInt CUnhintedOutlineCache::CacheUnhintedOutline(const TUnhintedOutlineId &aOutlineId, + TAny* const aData, const TInt aLength, TAny *&aOutline, TInt &aLen) + { +#ifdef _DEBUG + GetCacheState(__func__); +#endif + if ((TUint32)iCacheMemMon.GetMemUsage() >= KFontTable_GlyphOutline_CacheMaxMem) + { + RDebug::Printf("Table/Glyph cache full. Unable to add new item."); + return KErrNoMemory; + } + + aLen = KErrGeneral; + TInt ret1= KErrNone; + + // make a copy of the outline data on the shared heap. + TAny *sharedCopy = iHeap->Alloc(aLength); + if (NULL == sharedCopy) + { + return KErrNoMemory; + } + + Mem::Copy(sharedCopy, aData, aLength); + + COutlineCacheItem *newItem = NULL; + TInt offset = PointerToOffset(sharedCopy, iHeap->Base()); + TRAP(ret1, newItem = new(ELeave) COutlineCacheItem(offset, aLength)); + if (KErrNone != ret1) + { + iHeap->Free(sharedCopy); + sharedCopy = NULL; + } + else + { + TRAP(ret1, iItemIdMap.InsertL(aOutlineId, newItem)); + if (KErrNone != ret1) + { + delete newItem; + iHeap->Free(sharedCopy); + sharedCopy = NULL; + } + else + { + iCacheMemMon.Inc(aLength); + aLen = aLength; + } + } + aOutline = sharedCopy; + return ret1; + } + +TInt CUnhintedOutlineCache::IncRefCount(const TUnhintedOutlineId &aOutlineId, + TInt aSessionHandle) + { +#ifdef _DEBUG + GetCacheState(__func__); +#endif + COutlineCacheItem **ret = iItemIdMap.Find(aOutlineId); + if (NULL != ret) + { + (*ret)->IncRefCount(aSessionHandle); + } + return (NULL==ret?KErrNotFound:KErrNone); + } + +TInt CUnhintedOutlineCache::DecRefCount(const TUnhintedOutlineId &aOutlineId, + TInt aSessionHandle) + { +#ifdef _DEBUG + GetCacheState(__func__); +#endif + COutlineCacheItem **ret = iItemIdMap.Find(aOutlineId); + if (NULL != ret) + { + TInt numUsers = (*ret)->DecRefCount(aSessionHandle); + if (0 == numUsers) + { + // There is no outstanding reference to the cache item. + iHeap->Free(OffsetToPointer((*ret)->iOffset, iHeap->Base())); + iCacheMemMon.Dec((*ret)->iLength); + delete (*ret); + iItemIdMap.Remove(aOutlineId); + } + } + return (NULL==ret?KErrNotFound:KErrNone); + } + +TInt CUnhintedOutlineCache::Find(const TUnhintedOutlineId &aOutlineId, TAny *&aData, + TInt &aLength) + { + COutlineCacheItem **ret = iItemIdMap.Find(aOutlineId); + TInt ret2 = KErrNone; + if (NULL != ret) + { + aData = OffsetToPointer((*ret)->iOffset, iHeap->Base()); + aLength = (*ret)->iLength; + } + else + { + ret2 = KErrNotFound; + } + return ret2; + } + + +TUint32 CUnhintedOutlineCache::IdHash(const TUnhintedOutlineId &outlineId) + { + // The hash value: + // bits 0-15: glyph id; + // bits 16-23: lower 8 bit of font file uid + // bits 24-27: lower 4 bit of the face index + // bit 28: 'isGlyphId' + TUint32 ret = 0; + ret |= (outlineId.iId & KOutlineGlyphIdHashMask); + ret |= (KOutlineFileUidHashMask & (outlineId.iFileUid.iUid << 16)); + ret |= (KOutlineFaceIndexHashMask & (outlineId.iFaceIndex << 24)); + ret = (ret % 701); + return ret; + } + +TBool CUnhintedOutlineCache::IdIdentity(const TUnhintedOutlineId &id1, const TUnhintedOutlineId &id2) + { + return id1.iId == id2.iId && id1.iFaceIndex == id2.iFaceIndex && + id1.iFileUid == id2.iFileUid; + } + +// hinted outline cache +#ifdef _DEBUG +TInt CHintedOutlineCache::GetCacheState(const char *func) + { + RDebug::Printf("%s called from %s: ", __func__, func); + int numSessions = 0, totalRef = 0; + THashMapIter it(iItemIdMap); + it.NextValue(); + while (it.CurrentValue()) + { + COutlineCacheItem **data = it.CurrentValue(); + int len = (*data)->iUsers.Count(); + numSessions += len; + for (int j = 0; j < len; ++j) + { + totalRef += (*data)->iUsers[j]->iRefCount; + } + it.NextValue(); + } + + TBuf<256> buf; + buf.Append(_L("Hinted outline cache: ")); + TInt numItems = iItemIdMap.Count(); + if (0 == numItems) + { + buf.Append(_L("empty. ")); + } + else + { + buf.AppendFormat(_L("%d glyphs, %d sessions, total refcount %d"), + numItems, numSessions, totalRef); + } + + RDebug::RawPrint(buf); + + return 0; + } +#endif + +TInt CHintedOutlineCache::CleanupCacheOnOpenFontRemoval(COpenFont *aFont) + { + THashMapIter it(iItemIdMap); + it.NextValue(); + while (it.CurrentValue()) + { + const THintedOutlineId *outlineId = it.CurrentKey(); + COutlineCacheItem **data = it.CurrentValue(); + + // loop body here! + if (outlineId->iFont == aFont) + { + iCacheMemMon.Dec((*data)->iLength); + iHeap->Free(OffsetToPointer((*data)->iOffset, iHeap->Base())); + delete (*data); + iItemIdMap.Remove(*outlineId); + } + // end loop body + + it.NextValue(); + } + return KErrNone; + } + +TInt CHintedOutlineCache::CleanupCacheOnFbsSessionTermination(TInt aSessionHandle) + { + THashMapIter it(iItemIdMap); + it.NextValue(); + while (it.CurrentValue()) + { + const THintedOutlineId *outlineId = it.CurrentKey(); + COutlineCacheItem **data = it.CurrentValue(); + + // loop body here! + TInt id = 0; + TInt ret = (*data)->FindUser(aSessionHandle, &id); + if (KErrNone == ret) + { + delete (*data)->iUsers[id]; + (*data)->iUsers.Remove(id); + if (0 == (*data)->iUsers.Count()) + { + iCacheMemMon.Dec((*data)->iLength); + iHeap->Free(OffsetToPointer((*data)->iOffset, iHeap->Base())); + delete (*data); + iItemIdMap.Remove(*outlineId); + } + } + // end loop body + + it.NextValue(); + } + + return KErrNone; + } + + +CHintedOutlineCache::CHintedOutlineCache(RHeap *aHeap, TFontTableGlyphOutlineCacheMemMonitor &aMon): + iCacheMemMon(aMon), iHeap(aHeap), + iItemIdMap(THashFunction32(CHintedOutlineCache::IdHash), + TIdentityRelation(CHintedOutlineCache::IdIdentity)) + { + // a null constructor + } + +TInt CHintedOutlineCache::CacheHintedOutline(const THintedOutlineId &aOutlineId, + TAny* aData, TInt aLength, TAny *&aOutline, TInt &aLen) + { +#ifdef _DEBUG + GetCacheState(__func__); +#endif + if ((TUint32)iCacheMemMon.GetMemUsage() >= KFontTable_GlyphOutline_CacheMaxMem) + { + RDebug::Printf("Table/Glyph cache full. Unable to add new item."); + return KErrNoMemory; + } + + aLen = KErrGeneral; + TInt ret = KErrNone; + // make a copy of the outline data on the shared heap. + TAny *sharedCopy = iHeap->Alloc(aLength); + if (NULL == sharedCopy) + { + return KErrNoMemory; + } + + Mem::Copy(sharedCopy, aData, aLength); + + COutlineCacheItem *newItem = NULL; + TInt offset = PointerToOffset(sharedCopy, iHeap->Base()); + TRAP(ret, newItem = new(ELeave) COutlineCacheItem(offset, aLength)); + if (KErrNone != ret) + { + iHeap->Free(sharedCopy); + sharedCopy = NULL; + } + else + { + TRAP(ret, iItemIdMap.InsertL(aOutlineId, newItem)); + if (KErrNone != ret) + { + delete newItem; + iHeap->Free(sharedCopy); + sharedCopy = NULL; + } + else + { + iCacheMemMon.Inc(aLength); + aLen = aLength; + } + } + aOutline = sharedCopy; + return ret; + } + +TInt CHintedOutlineCache::IncRefCount(const THintedOutlineId &aOutlineId, + TInt aSessionHandle) + { +#ifdef _DEBUG + GetCacheState(__func__); +#endif + COutlineCacheItem **data = iItemIdMap.Find(aOutlineId); + if (NULL != data) + { + (*data)->IncRefCount(aSessionHandle); + } + return (NULL==data?KErrNotFound:KErrNone); + } + +TInt CHintedOutlineCache::DecRefCount(const THintedOutlineId &aOutlineId, + TInt aSessionHandle) + { +#ifdef _DEBUG + GetCacheState(__func__); +#endif + COutlineCacheItem **data = iItemIdMap.Find(aOutlineId); + if (NULL != data) + { + TInt numUsers = (*data)->DecRefCount(aSessionHandle); + if (0 == numUsers) + { + // There is no outstanding reference to the cache item. + iCacheMemMon.Dec((*data)->iLength); + iHeap->Free(OffsetToPointer((*data)->iOffset, iHeap->Base())); + delete (*data); + iItemIdMap.Remove(aOutlineId); + } + } + return (NULL==data?KErrNotFound:KErrNone); + } + +TInt CHintedOutlineCache::Find(const THintedOutlineId &aOutlineId, + TAny *&aData, TInt &aLength) + { + COutlineCacheItem **ret = iItemIdMap.Find(aOutlineId); + TInt ret2 = KErrNone; + if (NULL != ret) + { + aData = OffsetToPointer((*ret)->iOffset, iHeap->Base()); + aLength = (*ret)->iLength; + } + else + { + ret2 = KErrNotFound; + } + return ret2; + } + + +TUint32 CHintedOutlineCache::IdHash(const THintedOutlineId &outlineId) + { + // The hash value: + // bits 0-15: the outline id + // bits 16-27: the lower 12 bits of the font pointer + // bit 28: 'isGlyphId' + + TUint32 ret = 0; + ret |= (KOutlineGlyphIdHashMask & outlineId.iId); + ret |= (KOutlineFontPtrHashMask & (((TUint32)outlineId.iFont) << 16)); + ret = ret % 701; + return ret; + } + +TBool CHintedOutlineCache::IdIdentity(const THintedOutlineId &id1, const THintedOutlineId &id2) + { + return id1.iId == id2.iId && id1.iFont == id2.iFont; + } +// hinted cache + + +CFontStore::CFontStore(RHeap* aHeap): + iKPixelWidthInTwips(KDefaultPixelWidthInTwips), + iKPixelHeightInTwips(KDefaultPixelHeightInTwips), + iFs(), + iHeap(aHeap), + iFontStoreFileList(KDefaultArrayGranularity), // list of EPOC Bitmap font files loaded + iTypefaceList(KDefaultArrayGranularity), + iFontBitmapList(KDefaultArrayGranularity), + iTypefaceFontBitmapList(KDefaultArrayGranularity), + iOpenFontFileList(KDefaultArrayGranularity), // list of 'Open Font' files loaded + iOpenFontRasterizerList(KDefaultArrayGranularity), // open rasterizers, in load order + iOpenFontUid(1), + iDefaultBitmapType(EMonochromeGlyphBitmap), + iShaperFactoryList(KDefaultArrayGranularity), + iOpenFontShaperCacheMemUsage(0), + iNumberOfShaperCaches(0), + iOpenFontTypefaceSupportList(KDefaultArrayGranularity), // list of Open Font typefaces available + iUniqueFontIdCount(0) // used to give every font a unique id + { + } + +void CFontStore::ConstructL() + { + // Cache is placed in the shared heap + iOpenFontSessionCacheList = (COpenFontSessionCacheList*)iHeap->AllocL(sizeof(COpenFontSessionCacheList)); + new(iOpenFontSessionCacheList) COpenFontSessionCacheList; + + CTypefaceStore::ConstructL(); + User::LeaveIfError(iFs.Connect()); + + TMachineInfoV1Buf machineInfoBuffer; + User::LeaveIfError(UserHal::MachineInfo(machineInfoBuffer)); + + //Create Handles which may be used by Fntstore + iHandleArray = new(ELeave) RArray(); + + RSemaphore SessionCacheSem; + TInt ret = SessionCacheSem.CreateGlobal(KSessionCacheSemaphoreName,KSessionCacheSemaphoreCount); + if(ret == KErrAlreadyExists) + { + User::LeaveIfError(SessionCacheSem.OpenGlobal(KSessionCacheSemaphoreName)); + } + else if (ret != KErrNone) + { + User::LeaveIfError(ret); + } + ret = iHandleArray->Append(SessionCacheSem); + if(ret != KErrNone) + { + SessionCacheSem.Close(); + User::Leave(ret); + } + + const TSize twipSize = machineInfoBuffer().iPhysicalScreenSize; + const TSize pixelSize = machineInfoBuffer().iDisplaySizeInPixels; + + if (twipSize.iWidth > 0 && pixelSize.iWidth > 0) + iKPixelWidthInTwips = twipSize.iWidth * 1000 / pixelSize.iWidth; + + if (twipSize.iHeight > 0 && pixelSize.iHeight > 0) + iKPixelHeightInTwips = twipSize.iHeight * 1000 / pixelSize.iHeight; + + iCacheMemMon = new(ELeave) TFontTableGlyphOutlineCacheMemMonitor; + iUnhintedOutlineCache = new(ELeave) CUnhintedOutlineCache(iHeap, *iCacheMemMon); + iHintedOutlineCache = new(ELeave) CHintedOutlineCache(iHeap, *iCacheMemMon); + iFontTableCache = new(ELeave) CFontTableCache(iHeap, *iCacheMemMon); + + } + +/** Creates a new CFontStore object. + +Sets iKPixelWidthInTwips and iKPixelHeightInTwips. + +Sets the default bitmap type, used when getting bitmap fonts, to EMonochromeGlyphBitmap. + +Also initialises other private member variable values . + +@param aHeap A pointer to the heap class used for memory allocation. +@leave KErrNoMemory Insufficient memory available on the heap. */ +EXPORT_C CFontStore *CFontStore::NewL(RHeap* aHeap) + { + User::LeaveIfNull(aHeap); + CFontStore *fontstore = new(ELeave) CFontStore(aHeap); + CleanupStack::PushL(fontstore); + fontstore->ConstructL(); + CleanupStack::Pop(fontstore); + return fontstore; + } + +/** Destructor. */ +EXPORT_C CFontStore::~CFontStore() + { + // Remove All font files, and Reset associated arrays + RemoveFile(KNullUid); + iOpenFontRasterizerList.ResetAndDestroy(); + iShaperFactoryList.ResetAndDestroy(); + if (iOpenFontSessionCacheList) + { + iOpenFontSessionCacheList->Delete(iHeap); + iHeap->Free(iOpenFontSessionCacheList); + } + if (iHandleArray) + { + for (TInt i = 0; i < iHandleArray->Count(); i++) + { + (*iHandleArray)[i].Close(); + } + iHandleArray->Close(); + delete iHandleArray; + } + iFs.Close(); + + delete iFontTableCache; + delete iUnhintedOutlineCache; + delete iHintedOutlineCache; + delete iCacheMemMon; + } + + +// local utility functions +// reads bytes from file, if the requested number of bytes are not available it leaves +void ReadFromFileL(RFile& aFile, TDes8& aDes, TInt aLength) + { + User::LeaveIfError(aFile.Read(aDes, aLength)); + if (aDes.Length() != aLength) + { +#ifdef _DEBUG + RDebug::Print(_L("EOF reading structure from font file\n")); +#endif + User::Leave(KErrCorrupt); + } + } + +// local function(s) to read values from buffer & validate them +TUint TtfTableTagFromBufferL(TDes8& aDes) + { + TUint value = 0; + for (TUint index = 0; index < 4;) + { + TUint temp = static_cast(aDes[index++]); + // must be ASCII character between 32 & 126 inclusive (per Apple's TTF specification document) + if ( (temp < 32) || (temp > 126) ) + { + User::Leave(KErrCorrupt); +#ifdef _DEBUG + RDebug::Print(_L("invalid ASCII character (0x%x) in ttf table tag\n"), temp); +#endif + } + value = (value << 8) | temp; + } + return value; + } + +/* Sanity check for TrueType Font, checks that the font tables are sensible. +*/ +void CFontStore::SanityCheckForTtfL(RFile& aFontFile, TUint aFontFileSize, TBool aStrictChecking) + { +#if defined(_DEBUG) + RDebug::Print(_L("TTF File Size is %u (0x%x) bytes\n"), aFontFileSize, aFontFileSize); +#endif + + // check the Offset Table at the start of the file + TBuf8<16> fileBuffer; + + ReadFromFileL(aFontFile, fileBuffer, 12); + TUint numTables = (fileBuffer[4] << 8) | (fileBuffer[5]); + TUint searchRange = (fileBuffer[6] << 8) | (fileBuffer[7]); + TUint entrySelector = (fileBuffer[8] << 8) | (fileBuffer[9]); + TUint rangeShift = (fileBuffer[10] << 8) | (fileBuffer[11]); + + const TInt tableStart = 12 + (numTables << 4); // lowest possible address for actual table data + + if ( (numTables == 0) || (numTables & 0xF0000000) || (tableStart > aFontFileSize) ) + { +#ifdef _DEBUG + RDebug::Print(_L("# of tables (%i) in ttf is invalid\n"), numTables); +#endif + User::Leave(KErrCorrupt); + } + +#if defined(_DEBUG) && defined(VERBOSE_DEBUG) + // scalar type is 0x00010000 for Windows fonts, other possible values include 0x74727565 and 0x74797031: not checked + TUint scalarType = (fileBuffer[0] << 24) | (fileBuffer[1] << 16) | (fileBuffer[2] << 8) | (fileBuffer[3]); + RDebug::Print(_L("ttf scalarType is 0x%x, # of tables is %u\n"), scalarType, numTables); + RDebug::Print(_L("searchRange is 0x%x, entrySelector is 0x%x, rangeShift is 0x%x\n"), + searchRange, entrySelector, rangeShift); +#endif + + // check searchRange, entrySelector & rangeShift values + // (some not quite TTF files fail the rangeShift check) + if ( (searchRange < 16) || (entrySelector > 24) + || (aStrictChecking && (rangeShift != ( (numTables << 4) - searchRange )) ) ) + { +#ifdef _DEBUG + RDebug::Print(_L("searchRange (0x%x), entrySelector (0x%x) or rangeShift (0x%x) invalid for numTables (%i)\n"), + searchRange, entrySelector, rangeShift, numTables); +#endif + User::Leave(KErrCorrupt); + } + + // entrySelector is defined as Log2(Maximum power of 2 <= nmumTables) + TUint exp = 1 << entrySelector; // log to exponent + if ( (numTables < exp) || (numTables > (exp << 1)) ) + { +#ifdef _DEBUG + RDebug::Print(_L("entrySelector (0x%x) wrong for numTables(%i)\n"), entrySelector, numTables); +#endif + User::Leave(KErrCorrupt); + } + + // easy checks on the table directory + TInt totalFontSize = tableStart; // accumulated total directories plus table sizes + TInt highestTableEnd = 0; // highest value found for table start plus table length + TUint lastTableTag = 0; // to check that tags are in order + TInt tableNum = 0; + + do + { // each entry is 16 bytes, (though we don't check the checksum) + ReadFromFileL(aFontFile, fileBuffer, 16); + TUint tableTag = TtfTableTagFromBufferL(fileBuffer); + TUint offset = (fileBuffer[8] << 24) | (fileBuffer[9] << 16) | (fileBuffer[10] << 8) | (fileBuffer[11]); + TUint length = (fileBuffer[12] << 24) | (fileBuffer[13] << 16) | (fileBuffer[14] << 8) | (fileBuffer[15]); + +#if defined(_DEBUG) && defined(VERBOSE_DEBUG) + RDebug::Print(_L("ttf table tag ('%c%c%c%c'): offset is 0x%x, length is 0x%x\n"), + tableTag >> 24, (tableTag >> 16) & 0x7F, (tableTag >> 8) & 0x7F, tableTag & 0x7F, + offset, length); +#endif + length = (length + 3) & ~3; // round up, all tables must be a multiple of 4 bytes for checksumming + + // table Tags must be unique & in order + if (tableTag <= lastTableTag) + { +#ifdef _DEBUG + RDebug::Print(_L("ttf table tag ('%c%c%c%c') is out of order\n"), + tableTag >> 24, (tableTag >> 16) & 0x7F, (tableTag >> 8) & 0x7F, tableTag & 0x7F); +#endif + User::Leave(KErrCorrupt); + } + + + // the offset must be 4-byte aligned, and after the table directory + // offset + length must be bigger than the start offset (!) + TInt end = length + offset; + if ( (offset & 3) || (offset < tableStart) || (length == 0) || (end < offset) || (end > aFontFileSize)) + { +#ifdef _DEBUG + RDebug::Print(_L("offset (0x%x) or length (0x%x) are bad\n"), offset, length); +#endif + User::Leave(KErrCorrupt); + } + + lastTableTag = tableTag; + totalFontSize += length; + if (end > highestTableEnd) + { + highestTableEnd = end; + } + } + while (++tableNum < numTables); + +#if defined(_DEBUG) && defined(VERBOSE_DEBUG) + RDebug::Print(_L("last address used by any table is 0x%x, Minimum font file size to hold all tables is 0x%x\n"), + highestTableEnd, totalFontSize); +#endif + + // for single font files highestTableEnd & totalFontSize should be the same + if (highestTableEnd != totalFontSize) + { +#ifdef _DEBUG + RDebug::Print(_L("Total Font Size (0x%x) is different from end of the last table (0x%x)\n"), + highestTableEnd, totalFontSize); +#endif + User::Leave(KErrCorrupt); + } + } + +/* Sanity checks on font files, currently only knows about TrueType Font files: .ttf and .otf +Protects FBserv / the client and the rasterizer plug-in from grossly corrupt data. +@leave KErrCorrupt if the font tables are daft +*/ +void CFontStore::SanityCheckFontFileL(TParse& aParse) + { + + // try to open the file and getting the file size + RFile fontFile; + const TInt openError = fontFile.Open(iFs, aParse.FullName(), EFileRead | EFileShareReadersOnly); +#ifdef _DEBUG + if (KErrNone != openError) + { + const TDesC& fileName = aParse.FullName(); + RDebug::Print(_L("Sanity checking font file \"%S\", file open gave error %d\n"), &fileName, openError); + } +#endif + User::LeaveIfError(openError); + CleanupClosePushL(fontFile); + TInt fontFileSize = 0; + User::LeaveIfError(fontFile.Size(fontFileSize)); + + if (fontFileSize == 0) + { // no font can be zero length! +#ifdef _DEBUG + RDebug::Print(_L("font file size (%i) is zero\n"), fontFileSize); +#endif + User::Leave(KErrCorrupt); + } + else + { + const TDesC& fileExt = aParse.Ext(); + // TrueType fonts + _LIT(KFntStoreTrueTypeExtension,".ttf"); + // OpenType fonts + _LIT(KFntStoreOpenTypeExtension,".otf"); + // other font files that follow TTF format + _LIT(KFntStoreCccFontFileExtension,".ccc"); + + if ( (0 == fileExt.CompareF(KFntStoreTrueTypeExtension)) || (0 == fileExt.CompareF(KFntStoreOpenTypeExtension)) ) + { // uses TrueType file format, perform strict format check + SanityCheckForTtfL(fontFile, fontFileSize, ETrue); + } + else if (0 == fileExt.CompareF(KFntStoreCccFontFileExtension)) + { // uses nearly TrueType file format, perform slightly less strict format check + SanityCheckForTtfL(fontFile, fontFileSize, EFalse); + } + + // extendible if required for other font file types ... + } + + CleanupStack::PopAndDestroy(&fontFile); + } + + +/** Finds or creates a font file object to support a font file. The specified font +file must be accessible to any process, i.e. not located inside an +application's private directory. + +If an appropriate font file object exists then no new open font file is created. +In this case the reference count of the font file object is incremented. + +Notes: + +If aName is recognised as an open font file, creates a COpenFontFile, which +will manage the font file specified by aName, and adds it to the file store's +list of open font files. + +The list of open font files is used when getting the nearest font for a font +specification (i.e. by the GetNearestFont...() functions of this class) if +the font is generated via a rasterizer. + +The appropriate rasterizer, which supports the font format of the font file, +is used to generate the open font file using COpenFontRasterizer::NewFontFileL(). + +If aName is not recognised as an open font file then CFontStoreFile tries to open +the file as a Symbian Bitmap font. + +@param aName The full path and filename of the font file to be supported. +@return The UID of the font file object supporting aName. +@leave KErrNotSupported if the file is not recognised at all +@leave KErrCorrupt if the font file data does not make sense +@leave or another system-wide error +*/ +EXPORT_C TUid CFontStore::AddFileL(const TDesC& aName) + { + TParse fontFilename; + User::LeaveIfError(iFs.Parse(aName, fontFilename)); + + // increment reference count if font file is already loaded + TUid fontUid = KNullUid; + + if (IncRefCountOfLoadedFont(fontFilename, fontUid)) + { + return fontUid; + } + + // Do not validate fonts on Z: (assumed to be ROM created with valid fonts) + if (!FileIsOnZ(fontFilename)) + { + // file is not open - check that the file exists and has a plausible content + SanityCheckFontFileL(fontFilename); + } + + AddSanityCheckedFontL(fontFilename, fontUid); + + return fontUid; + } + +/** +Finds or creates a font file object to support a font file. +@param aFileName The filename to check +@param aUid The list to check +@see CFontStore::AddFileL +*/ +void CFontStore::AddSanityCheckedFontL(const TParse& aFileName, TUid& aUid) + { + // Try loading the file as an Open Font + if (!LoadFileAsOpenFontL(aFileName, aUid)) + { + // It could not be recognised as an Open Font file so load it as an EPOC bitmap font file. + // (This always succeeds or Leaves.) + aUid = LoadFileAsBitmapFontL(aFileName); + } + } + + +// Remove a Font File - called via the Cleanup Stack if a leave occurs during font install +void CFontStore::CleanupRemoveFontFile(TAny* aCleanupInfo) + { + TCleanupRemoveFontFile* cleanupInfo = (TCleanupRemoveFontFile *) aCleanupInfo; + cleanupInfo->iFontStore->RemoveFile(cleanupInfo->iFontUid); + } + + +/** Search through the rasterizers for one that will open the font filename. + +Can leave if the rasterizer encounters an error, such as unexpected end of file, nonsense data, no memory. + +@param aName full filename to open +@param aFontUid set to the font file UID if it is already loaded +@return ETrue if the font file is loaded, otherwise EFalse +@internalComponent +*/ +TBool CFontStore::LoadFileAsOpenFontL(const TParse& aFileName, TUid& aFontUid) + { + const TDesC& fullName = aFileName.FullName(); + + // ask each of the rasterizers in turn to create a COpenFontFile object. + const TInt rasterizerCount = iOpenFontRasterizerList.Count(); + for (TInt index = 0; index < rasterizerCount; index++) + { + COpenFontFile* openFontFile = iOpenFontRasterizerList[index]->NewFontFileL(iOpenFontUid, fullName, iFs); + if (NULL != openFontFile) + { + /* Uids for Open Fonts are allocated in order; the + one for the COpenFontFile just created won't match any existing one. + (When a file is removed, the fake Uid will match, because the one that was returned here is used.) + */ + CleanupStack::PushL(openFontFile); + openFontFile->SetFontStoreL(this); + iOpenFontFileList.AppendL(openFontFile); + openFontFile->IncRefCount(); + CleanupStack::Pop(openFontFile); + + TInt typefaceAddError = AddTypefacesToSupportList(openFontFile); + if (typefaceAddError) + { + // cleanup + RemoveFile(openFontFile->Uid()); + // throw the error + User::Leave(typefaceAddError); + } + + /* + iOpenFontUid is the fake Uid used for new font files. It is made modulo a 'zillion' (2^28) + so that it cannot conflict with real Uids, which are >= 2^28. It starts at 1 so that + it does not conflict with the value 0 (KNullUid) which is used as a sentinel in + CFontStore::RemoveFileL. + */ + ++iOpenFontUid; + iOpenFontUid = iOpenFontUid % 0x1000000; + + aFontUid = openFontFile->Uid(); + return ETrue; + } + } + return EFalse; + } + + +/** Search loaded fonts for filename, and increment the reference count +@param aParse full filename to search for +@return the font file UID +@leave KErrNotSupported or another system wide error code +@internalComponent +*/ +TUid CFontStore::LoadFileAsBitmapFontL(const TParse& aParse) + { + // open the file, presuming it is a bitmap font + CFontStoreFile* fontStoreFile = CFontStoreFile::NewL(aParse, iFs); + + // See if a font with this UID is already open + TInt match = FindBitmapFontFileIndexByUid(fontStoreFile->iCollectionUid); + if (match != KErrNotFound) // The file is open. + { // close the new duplicate, inc the reference count + delete fontStoreFile; + fontStoreFile = iFontStoreFileList[match]; + fontStoreFile->iUsageCount++; + } + else + { + CleanupStack::PushL(fontStoreFile); + iFontStoreFileList.AppendL(fontStoreFile); + CleanupStack::Pop(fontStoreFile); + + // special object to removes the font file if a leave occurs during font install + TCleanupRemoveFontFile cleanupHelper(this, fontStoreFile->iCollectionUid); + CleanupStack::PushL(TCleanupItem(CleanupRemoveFontFile, &cleanupHelper)); + // install the new font + InternalizeFontStoreFileL(fontStoreFile, fontStoreFile->iFontVersion); + CleanupStack::Pop(&cleanupHelper); // CleanupRemoveFontFile + } + return fontStoreFile->iCollectionUid; + } + + +/** Search open Bitmap font files for matching UID +@param aUid UID to search for +@return The index of the matching item in iFontStoreFileList[] array, or KErrNotFound +@internalComponent +*/ +TInt CFontStore::FindBitmapFontFileIndexByUid(TUid aUid) + { + const TInt fontFileCount = iFontStoreFileList.Count(); + for (TInt index = 0; index < fontFileCount; index++) + { + if (iFontStoreFileList[index]->iCollectionUid == aUid) + { + return index; + } + } + return KErrNotFound; + } + + +/** Search loaded fonts for filename, and increment the reference count +@param aName full filename to search for +@param aFontUid set to the font file UID if it is already loaded +@return ETrue if the font file is already loaded, otherwise EFalse +@internalComponent +*/ +TBool CFontStore::IncRefCountOfLoadedFont(const TParse& aFileName, TUid& aFontUid) + { + const TDesC& fullName = aFileName.FullName(); + + // Is it already in the Open Font list? Compare by full filename, not (fake) Uid; + const TInt openFontCount = iOpenFontFileList.Count(); + TInt i = 0; + for (i = 0; i < openFontCount; ++i) + { + COpenFontFile* openFontFile = iOpenFontFileList[i]; + if (fullName.CompareF(openFontFile->FileName()) == 0) + { + // Open Font file already loaded + openFontFile->IncRefCount(); + aFontUid = openFontFile->Uid(); + return ETrue; + } + } + + // already open as an EPOC bitmap font file? + const TInt fontFileCount = iFontStoreFileList.Count(); + for (i = 0; i < fontFileCount; i++) + { + CFontStoreFile* fontStoreFile = iFontStoreFileList[i]; + if (fullName.CompareF(fontStoreFile->FullName()) == 0) + { + // font file already loaded + ++(fontStoreFile->iUsageCount); + aFontUid = fontStoreFile->iCollectionUid; + return ETrue; + } + } + return EFalse; + } + + +/** Releases a hold on one or all font file objects (COpenFontFiles or CFontStoreFiles). + +If aFileUid identifies a font file object, then the reference count for this +object is decremented. If this brings the reference count down to zero then +the font file object and typefaces associated with this file are removed from +the font store, provided no fonts associated with this file are being accessed. +If one or more fonts are being accessed then the file removal request will be ignored. + +If, on the other hand, aFileUid's value is NULL, then all font file objects +are removed, along with all fonts and typefaces in the font store, provided +that no fonts in the font store are being accessed (i.e. iFontAccess is empty), +otherwise it has no effect. + +(If aFileUid is invalid, then no objects are removed.) + +@param aFileUid UID of a hold on a font file object to be released, or KNullUid +if all font file objects are to be removed. +*/ +EXPORT_C void CFontStore::RemoveFile(TUid aFileUid) + { + TInt i, count; + if (aFileUid == KNullUid) // this means 'delete all files' + { + if(iFontAccess) + { + TInt count = iFontAccess->Count(); + for (TInt i = 0; i < count; i++) + if((*iFontAccess)[i].iAccessCount) + return; + } + if (iFontTableCache && iFontTableCache->HasOutstandingRefCount()) + { + // disallow font file removal if any font tables are still cached + return; + } + + iTypefaceList.ResetAndDestroy(); + count = iFontBitmapList.Count(); + for (TInt i = 0; i < count; i++) + iFontBitmapList[i]->Release(); + iFontBitmapList.Reset(); + iTypefaceFontBitmapList.Reset(); + iFontStoreFileList.ResetAndDestroy(); + iOpenFontFileList.ResetAndDestroy(); + iOpenFontTypefaceSupportList.ResetAndDestroy(); + } + else + { + // See if it's an Open Font file. + count = iOpenFontFileList.Count(); + for (i = 0; i < count; i++) + { + TInt fontAccessCount; + if (iOpenFontFileList[i]->Uid() == aFileUid) + { // found the file + if (iFontAccess) + { // Check to see if there are any references before we consider deleting + fontAccessCount = iFontAccess->Count(); + for (TInt kk = 0; kk < fontAccessCount; ++kk) + { + CBitmapFont* bitmapFont = reinterpret_cast((*iFontAccess)[kk].iFont); + COpenFont* openFont = bitmapFont->OpenFont(); + if (openFont && openFont->File()->Uid() == aFileUid ) + { + if ((*iFontAccess)[kk].iAccessCount > 0) + return; // Outstanding reference found, so ignoring file removal request + } + } + } // Safe to proceed with removing file + // also check if there are outstanding references to any + // table in that file. + if (iFontTableCache && iFontTableCache->HasOutstandingRefCountWithUid(aFileUid)) + { + return; // outstanding reference to font table found. + } + + // Safe to proceed with removing file + if (iOpenFontFileList[i]->DecRefCount()) + { // unload the font file + RemoveTypefacesFromSupportList(iOpenFontFileList[i]); + //linked fonts deleted from this destructor + delete iOpenFontFileList[i]; + iOpenFontFileList.Delete(i); + } + return; + } + } + + // Finds first fontstorefile with correct id + TInt index = FindBitmapFontFileIndexByUid(aFileUid); + if (index != KErrNotFound) // Checks fontstore file has been found + { + iFontStoreFileList[index]->iUsageCount--; + if (!iFontStoreFileList[index]->iUsageCount) + { + TInt tfcount = iTypefaceFontBitmapList.Count(); + for (i=tfcount-1; i>=0; i--) + if (aFileUid == iTypefaceFontBitmapList[i].iFontBitmap->FontStoreFile()->iCollectionUid) + iTypefaceFontBitmapList.Delete(i); + count = iFontBitmapList.Count(); + for (i=count-1; i>=0; i--) + { + + if (aFileUid==iFontBitmapList[i]->FontStoreFile()->iCollectionUid) + { + iFontBitmapList[i]->Release(); + iFontBitmapList.Delete(i); + } + } + count = iTypefaceList.Count(); + for (i=count-1; i>=0; i--) + { + TBool inlist=EFalse; + tfcount = iTypefaceFontBitmapList.Count(); + for (TInt j=0; j height_diff) + height_diff = -height_diff; + } + score += KFontMaxScoreForHeight - height_diff; + + if (aCandidateFontSpec.IsItalic() == aIdealFontSpec.IsItalic() && + (0 < aCandidateFontSpec.SlantFactor()) == (0 < aIdealFontSpec.SlantFactor())) + { + score += KFontMatchScoreForExactItalicAndSlant; + } + else if ((aCandidateFontSpec.IsItalic() && 0 < aIdealFontSpec.SlantFactor()) || + (aIdealFontSpec.IsItalic() && 0 < aCandidateFontSpec.SlantFactor())) + { + score += KFontSimilarScoreForItalicAndSlant; + } + + if (aCandidateFontSpec.IsBold() == aIdealFontSpec.IsBold()) + { + score += KFontMatchScoreForBold; + } + + TUint effectsFlag = aIdealFontSpec.Effects() & aCandidateFontSpec.Effects(); + TBool isShadowOutlineEffects = EFalse; + + if(effectsFlag & FontEffect::EOutline) + { + score += KFontMatchScoreForOutlineOrShadow; + isShadowOutlineEffects = ETrue; + } + if(effectsFlag & FontEffect::EDropShadow) + { + score += KFontMatchScoreForOutlineOrShadow; + isShadowOutlineEffects = ETrue; + } + + //Match for bitmap glyph type only when effects are off. + //BitmapType in aIdealFontSpec will be set to EFourColourBlendGlyphBitmap by rasterizer only + //when any of the effects (outline/shadow) are on and if it supports outline and shadow fonts. + if(!isShadowOutlineEffects && (aCandidateFontSpec.BitmapType() == aIdealFontSpec.BitmapType())) + { + score += KFontMatchScoreForBitmapType; + } + if (aCandidateFontSpec.IsMonoWidth() == aIdealFontSpec.IsMonoWidth()) + { + score += KFontMatchScoreForMonoSpace; + } + if (aCandidateFontSpec.IsSerif() == aIdealFontSpec.IsSerif()) + { + score += KFontMatchScoreForSerif; + } + + return score; + } + + +/** +Find and load the nearest Open Font by +1. using aDesiredFontSpec to check if its already loaded, +2. using aActualFontSpec to partially match and create a new font. +Partial match means typeface name must match, other attributes need not match. +Font must fit vertically within the specified max height if given. + +@param aFont Output, is the returned font. +@param aActualFontSpec Output, is used to represent the returned font and changed to twips. +@param aDesiredFontSpec Input, the desired font specification +@param aMaxHeight Input, the maximum height in Pixels, or 0 +@post if any Open Fonts are available this will always return something +*/ +void CFontStore::GetNearestOpenFontInPixelsL( + CFont*& aFont, + TOpenFontSpec& aActualFontSpec, + const TOpenFontSpec& aDesiredFontSpec, + TInt aMaxHeight) + { + // Set the baseline offset appropriately for superscript or subscript. + TAlgStyle algstyle; + algstyle.iBaselineOffsetInPixels = BaselineOffset(aActualFontSpec.Height(), aActualFontSpec.PrintPosition()); + + // Determine if an open font with a perfect match is already loaded. + if (IsFontLoaded(aFont, algstyle, aDesiredFontSpec, aMaxHeight)) + { + aActualFontSpec = aDesiredFontSpec; + } + else + { // If not, find the nearest match for aActualFontSpec. + COpenFont* nearestFont = NULL; + + // fast search, if DO_LOADFONT_OPTIMIZATION is defined, search loaded font names for match + TInt errorName=GetNearestOpenFontInPixelsByFontName(nearestFont, aActualFontSpec, aDesiredFontSpec, aMaxHeight); + TInt errorSimilar=KErrNone; + + if (!nearestFont) + { + errorSimilar=GetNearestOpenFontInPixelsBySimilarity(nearestFont, aActualFontSpec, aDesiredFontSpec, aMaxHeight); + } + + // If an imperfect match was found, is it already loaded? If not, create a new CBitmapFont. + if (nearestFont) + { + // + // Results of everything above are stored in nearestFont, and aActualFontSpec + // First check if the not-exactly-matched font is already loaded + // aMaxHeight is 0 to prevent duplicate CBitmapFontObjects being created + // + if (IsFontLoaded(aFont, algstyle, aActualFontSpec, 0)) + { + delete nearestFont; + } + else + { + // Set the specification of the nearest match in twips. + TOpenFontSpec openFontSpec(aActualFontSpec); + openFontSpec.SetHeight(VerticalPixelsToTwips(openFontSpec.Height())); + CleanupStack::PushL(nearestFont); + aFont = NewFontL(openFontSpec, algstyle, nearestFont); + CleanupStack::Pop(nearestFont); + } + } + else + { + User::LeaveIfError(errorSimilar); + User::LeaveIfError(errorName); + } + } + } + + +/** Using the Desired Font Name try to find a matching font. + +@param aNearestOpenFont Output, nearest matching open font +@param aActualFontSpec Output, is used to represent the returned font +@param aDesiredFontSpec Input, the desired font specification +@param aMaxHeight Input, the maximum height in Pixels, or 0 +*/ +#if(DO_LOADFONT_OPTIMIZATION) +TInt CFontStore::GetNearestOpenFontInPixelsByFontName( + COpenFont*& aOpenFont, + TOpenFontSpec& aActualFontSpec, + const TOpenFontSpec& aDesiredFontSpec, + TInt aMaxHeight) + { + TOpenFontSpec actualFontSpec; + COpenFont* nearestFont = NULL; + + if (aMaxHeight == 0 && aDesiredFontSpec.Name().Length() > 0) // check if it is a request for OpenFont + { + TPtrC requestedName = aDesiredFontSpec.Name(); + // Typeface files may contain all those typefaces in a family, or may contain only some. + // The optimization first tries the ShortFullName of the typeface in case the typefaces are + // put into separate files. + + // First check FullName. The following assumes that there are never two COpenFontFiles in the + // list with the same ShortFullName. So italic and bold flags are not checked. + + const TInt openFontFileCount = iOpenFontFileList.Count(); + TInt index; + TInt typicalError = KErrNone; + for (index = 0; index < openFontFileCount; index++) + { + COpenFontFile *pFile = iOpenFontFileList[index]; + const TOpenFontFaceAttrib &faceAttrib = pFile->FaceAttrib(0); + + // Use short names. They are truncated to the same length as the request in TTypeface + if ((faceAttrib.ShortFullName().CompareF(requestedName)==0) && + (faceAttrib.IsBold() == aActualFontSpec.IsBold()) && + (faceAttrib.IsItalic() == aActualFontSpec.IsItalic()) ) + { + TInt error=pFile->GetNearestFontToDesignHeightInPixels( + iHeap, iOpenFontSessionCacheList, aActualFontSpec, iKPixelWidthInTwips, + iKPixelHeightInTwips, nearestFont, actualFontSpec); + + // search has finished if a match was found + if (nearestFont) + { + // need to copy the actual to the value that is going to be used down below + // to make a new font + aOpenFont = nearestFont; + aActualFontSpec = actualFontSpec; + return KErrNone; + } + else + { + if (error) + { + typicalError=error; + } + } + } + } + + // If the FullName match above has failed, then the request is being made by + // something other than a full name (assuming typeface is present). + // Although there may be more than one typeface in a file, + // It is not possible to conclude that ALL typefaces of the family are in one file. + // So to be safe, checks are made on italic and bold, possibly downgrading the optimization. + // Use short names. They are truncated to the same length as the request in TTypeface + for (index = 0; index < openFontFileCount; index++) + { + COpenFontFile *pFile = iOpenFontFileList[index]; + const TOpenFontFaceAttrib &faceAttrib = pFile->FaceAttrib(0); + + if( (faceAttrib.ShortFamilyName().CompareF(requestedName) == 0) && + (faceAttrib.IsItalic() == aDesiredFontSpec.IsItalic()) && + (faceAttrib.IsBold() == aDesiredFontSpec.IsBold()) ) + { + TInt error=pFile->GetNearestFontToDesignHeightInPixels( + iHeap, iOpenFontSessionCacheList, aActualFontSpec, iKPixelWidthInTwips, + iKPixelHeightInTwips, nearestFont, actualFontSpec); + + // search has finished if a match was found + if (nearestFont) + { + // need to copy the actual to the value that is going to be used down below + // to make a new font + aOpenFont = nearestFont; + aActualFontSpec = actualFontSpec; + return KErrNone; + } + else + { + if (error) + { + typicalError=error; + } + } + } + } + // no match + return typicalError; + } + // not open request + return KErrNone; + } +#else +TInt CFontStore::GetNearestOpenFontInPixelsByFontName( + COpenFont*& /* aOpenFont */, + TOpenFontSpec& /* aActualFontSpec */, + const TOpenFontSpec& /* aDesiredFontSpec */, + TInt /* aMaxHeight*/) + { // no match + return KErrNone; + } +#endif + + +/** Using the Desired Font Name try to find a matching font. + +@param aNearestOpenFont Output, nearest matching open font +@param aActualFontSpec Output, is used to represent the returned font +@param aDesiredFontSpec Input, the desired font specification +@param aMaxHeight Input, the maximum height in Pixels, or 0 +*/ +TInt CFontStore::GetNearestOpenFontInPixelsBySimilarity( + COpenFont*& aNearestOpenFont, + TOpenFontSpec& aActualFontSpec, + const TOpenFontSpec& aDesiredFontSpec, + TInt aMaxHeight) + { + const TInt openFontFileCount = iOpenFontFileList.Count(); + TOpenFontSpec nearestFontSpec; + COpenFont* nearestFont = NULL; + TInt nearestMatch = 0; + TInt typicalError=KErrNone; + for (TInt index = 0; index < openFontFileCount; index++) + { + // ask font file for its best match, if any + COpenFont* candidateFont = NULL; + TOpenFontSpec actualFontSpec; + TInt lastError=KErrNone; + if (aMaxHeight) + { + lastError=iOpenFontFileList[index]->GetNearestFontToMaxHeightInPixels( + iHeap, iOpenFontSessionCacheList, aActualFontSpec, iKPixelWidthInTwips, + iKPixelHeightInTwips, candidateFont, actualFontSpec, aMaxHeight); + } + else + { + lastError=iOpenFontFileList[index]->GetNearestFontToDesignHeightInPixels( + iHeap, iOpenFontSessionCacheList, aActualFontSpec, iKPixelWidthInTwips, + iKPixelHeightInTwips, candidateFont, actualFontSpec); + } + + // hold on to the best overall match + if (candidateFont) + { + const TInt candidateMatch = MatchFontSpecsInPixels( + actualFontSpec, aDesiredFontSpec, candidateFont->FontMaxHeight(), aMaxHeight); + + if (NULL == nearestFont || candidateMatch > nearestMatch) + { + if (nearestFont) + { + delete nearestFont; + } + nearestFont = candidateFont; + nearestMatch = candidateMatch; + nearestFontSpec = actualFontSpec; + } + else + { + // Font match is no better than the current nearestFont + // + // Note this object is newed in GetNearestFontInPixels each time + // a matching font is found. + delete candidateFont; + } + } + else + { + if (lastError) + { + typicalError=lastError; + } + } + } + + if (nearestFont != NULL) + { // result + aNearestOpenFont = nearestFont; + aActualFontSpec = nearestFontSpec; + return KErrNone; + } + else + { + return typicalError; + } + } + + +/** +Get the nearest bitmap font to aFontSpec and place it in aFont. Font must +fit vertically inside specified maximum height if given. GetNearestTypeface is +called which insists that there is at least one typeface. This function will always +succeed unless there is an out-of-memory error or other abnormal error. +Change aFontSpec to represent the returned font and change it to twips. +*/ +void CFontStore::GetNearestBitmapFontInPixelsL( + CFont*& aFont, + TFontSpec& aFontSpec, + TInt aMaxHeight) + { + aFontSpec.iTypeface = *GetNearestTypeface(aFontSpec.iTypeface); + TTypefaceFontBitmap tffb = GetNearestTypefaceFontBitmap(aFontSpec, aMaxHeight); + const TInt height = tffb.HeightInPixels(); + if (aFontSpec.iFontStyle.PrintPosition() != EPrintPosNormal) + { + aFontSpec.iHeight = SuperSubHeight(height, aFontSpec.iFontStyle.PrintPosition()); + tffb = GetNearestTypefaceFontBitmap(aFontSpec, aMaxHeight); + } + aFontSpec.iHeight = height; + TAlgStyle algstyle; + algstyle.SetIsBold( + EStrokeWeightBold == aFontSpec.iFontStyle.StrokeWeight() && + EStrokeWeightNormal == tffb.iFontBitmap->StrokeWeight()); + algstyle.SetIsItalic( + EPostureItalic == aFontSpec.iFontStyle.Posture() && + EPostureUpright == tffb.iFontBitmap->Posture()); + algstyle.SetIsMono(!aFontSpec.iTypeface.IsProportional() && tffb.iFontBitmap->IsProportional()); + TInt widthfactor = + ((tffb.iWidthFactor * tffb.iFontBitmap->FontStoreFile()->iKPixelAspectRatio * iKPixelWidthInTwips) + (500 * iKPixelHeightInTwips)) / (1000 * iKPixelHeightInTwips); + if (!widthfactor) + widthfactor = 1; + algstyle.SetWidthFactor(widthfactor); + algstyle.SetHeightFactor( tffb.iHeightFactor ); + algstyle.iBaselineOffsetInPixels = BaselineOffset(height, aFontSpec.iFontStyle.PrintPosition()); + if (IsFontLoaded(aFont, algstyle, aFontSpec, tffb.iFontBitmap->iUid)) + return; + TFontSpec spec(aFontSpec); + spec.iHeight = VerticalPixelsToTwips(height); + spec.iFontStyle.SetBitmapType(EMonochromeGlyphBitmap); + aFont = NewFontL(spec, algstyle, tffb.iFontBitmap); + } + +/** +Gets the font which is the nearest to the given font specification. + +Note that this deprecated function is replaced by the new @c GetNearestFontToDesignHeightInPixels() +yielding (virtually) the same result. However clients are strongly encouraged to use the new +@c GetNearestFontToMaxHeightInPixels() function instead. This will guarantee that every +character within any given text string will fit within the given amount of pixels, whereas the design +height is an aesthetic unit decided by the font designer without strict physical meaning, which +may result in cropped characters. + +@param aFont On return, contains a pointer to the nearest font. +@param aFontSpec The specification of the font to be matched. +@return KErrNone if successful; a system-wide error code otherwise. +@publishedAll +@deprecated Use GetNearestFontToDesignHeightInPixels +*/ +EXPORT_C TInt CFontStore::GetNearestFontInPixels(CFont*& aFont, const TFontSpec& aFontSpec) + { + return GetNearestFontToDesignHeightInPixels(aFont, aFontSpec); + } + +/** +Gets the font which is the nearest to the given font specification. + +Note that this deprecated function is replaced by the new @c GetNearestFontToDesignHeightInPixels() +yielding (virtually) the same result. However clients are strongly encouraged to use the new +@c GetNearestFontToMaxHeightInPixels() function instead. This will guarantee that every +character within any given text string will fit within the given amount of pixels, whereas the design +height is an aesthetic unit decided by the font designer without strict physical meaning, which +may result in cropped characters. + +@param aFont On return, contains a pointer to the nearest font. +@param aFontSpec The specification of the font to be matched. +@return KErrNone if successful; a system-wide error code otherwise. +@publishedAll +@deprecated Use GetNearestFontToDesignHeightInPixels +*/ +EXPORT_C TInt CFontStore::GetNearestFontInPixels(CFont*& aFont, const TOpenFontSpec& aFontSpec) + { + return GetNearestFontToDesignHeightInPixels(aFont, aFontSpec); + } + +/** +Gets the font which is the nearest to the given font specification. + +This new function replaces the deprecated @c GetNearestFontInPixels() yielding (virtually) the +same result. However clients are strongly encouraged to use the new +@c GetNearestFontToMaxHeightInPixels() function instead. This will guarantee that every +character within any given text string will fit within the given amount of pixels, whereas the design +height is an aesthetic unit decided by the font designer without strict physical meaning, which +may result in cropped characters. + +@param aFont On return, contains a pointer to the nearest font. +@param aFontSpec The specification of the font to be matched. +@return KErrNone if successful; a system-wide error code otherwise. +@publishedAll +@released +*/ +EXPORT_C TInt CFontStore::GetNearestFontToDesignHeightInPixels(CFont*& aFont, const TFontSpec& aFontSpec) + { + TOpenFontSpec spec(aFontSpec); + return GetNearestFontToDesignHeightInPixels(aFont, spec); + } + +/** +Gets the font which is the nearest to the given font specification. + +This new function replaces the deprecated @c GetNearestFontInPixels() yielding (virtually) the +same result. However clients are strongly encouraged to use the new +@c GetNearestFontToMaxHeightInPixels() function instead. This will guarantee that every +character within any given text string will fit within the given amount of pixels, whereas the design +height is an aesthetic unit decided by the font designer without strict physical meaning, which +may result in cropped characters. + +@param aFont On return, contains a pointer to the nearest font. +@param aFontSpec The specification of the font to be matched. +@return KErrNone if successful; a system-wide error code otherwise. +@publishedAll +@released +*/ +EXPORT_C TInt CFontStore::GetNearestFontToDesignHeightInPixels(CFont*& aFont, const TOpenFontSpec& aFontSpec) + { + return GetNearestFontInPixels(aFont, aFontSpec, 0); + } + +/** +Gets the font which is the nearest to the given font specification. + +The font and bitmap server returns a pointer to the nearest matching font +from those available. Matches to max height of font - this does its best +to return a font that will fit within the maximum height specified (but +note that variations due to hinting algorithms may rarely result in this +height being exceeded by up to one pixel). Problems can also be +encountered with bitmap fonts where the typeface exists but doesn't have +a font small enough. + +@param aFont On return, contains a pointer to the nearest font. +@param aFontSpec The specification of the font to be matched. +@param aMaxHeight The maximum height within which the font must fit. If maximum height +is greater than 1024 pixels, the function returns KErrTooBig. And returns KErrArgument +if equals to 1 pixel. This overrides the height specified in aFontSpec. +@return KErrNone if successful; a system-wide error code otherwise. +@publishedAll +@released +*/ +EXPORT_C TInt CFontStore::GetNearestFontToMaxHeightInPixels(CFont*& aFont, const TFontSpec& aFontSpec, TInt aMaxHeight) + { + TOpenFontSpec spec(aFontSpec); + return GetNearestFontToMaxHeightInPixels(aFont, spec, aMaxHeight); + } + +/** +Gets the font which is the nearest to the given font specification. + +The font and bitmap server returns a pointer to the nearest matching font +from those available. Matches to max height of font - this does its best +to return a font that will fit within the maximum height specified (but +note that variations due to hinting algorithms may rarely result in this +height being exceeded by up to one pixel). Problems can also be +encountered with bitmap fonts where the typeface exists but doesn't have +a font small enough. + +@param aFont On return, contains a pointer to the nearest font. +@param aFontSpec The specification of the font to be matched. +@param aMaxHeight The maximum height within which the font must fit. If maximum height +is greater than 1024 pixels, the function returns KErrTooBig. And returns KErrArgument +if equals to 1 pixel. This overrides the height specified in aFontSpec. +@return KErrNone if successful; a system-wide error code otherwise. +@publishedAll +@released +*/ +EXPORT_C TInt CFontStore::GetNearestFontToMaxHeightInPixels(CFont*& aFont, const TOpenFontSpec& aFontSpec, TInt aMaxHeight) + { + if (KMaxFontHeightInPixels < aMaxHeight) + { + return KErrTooBig; + } + if (aMaxHeight > 0 && aMaxHeight < KMinFontHeightInPixels) + { + return KErrArgument; + } + return GetNearestFontInPixels(aFont, aFontSpec, aMaxHeight); + } + +TInt CFontStore::GetNearestFontInPixels( + CFont*& aFont, + const TOpenFontSpec& aDesiredFontSpec, + TInt aMaxHeight) + { + aFont = NULL; + + // Determine the ideal version of the font spec. + TOpenFontSpec originalFontSpec = aDesiredFontSpec; + originalFontSpec.CompensateForAspectRatio(iKPixelWidthInTwips, iKPixelHeightInTwips); + TOpenFontSpec desiredFontSpec = originalFontSpec; + if (EDefaultGlyphBitmap == desiredFontSpec.BitmapType()) + { + desiredFontSpec.SetBitmapType(iDefaultBitmapType); + } + if (EPrintPosNormal != desiredFontSpec.PrintPosition()) + { + desiredFontSpec.SetHeight(SuperSubHeight(desiredFontSpec.Height(), desiredFontSpec.PrintPosition())); + } + TOpenFontSpec actualOpenFontSpec = desiredFontSpec; + + // Try to get an open font. + CFont* openFont = NULL; + TRAPD(error, GetNearestOpenFontInPixelsL( + openFont, actualOpenFontSpec, desiredFontSpec, aMaxHeight)); + + // Try to get a bitmap font - if getting open font failed or the match was not perfect. + CFont* bitmapFont = NULL; + TInt errorBitmap=KErrNone; + TOpenFontSpec actualBitmapFontSpec; + if (error || !openFont || actualOpenFontSpec != desiredFontSpec) + { + TFontSpec f; + originalFontSpec.GetTFontSpec(f); + if (iTypefaceList.Count() > 0) + { + TRAP(errorBitmap, GetNearestBitmapFontInPixelsL(bitmapFont, f, aMaxHeight)); + } + actualBitmapFontSpec = f; + actualBitmapFontSpec.CompensateForAspectRatio(iKPixelWidthInTwips, iKPixelHeightInTwips); + } + + //If both attempts fail then there is nothing more we can do... + if (!openFont && !bitmapFont) + { + //If an error caused no fonts to be returned then forward the error + if (error) + return error; + if (errorBitmap) + return errorBitmap; + } + // Choose the best candidate + if (NULL == openFont && NULL == bitmapFont) + { + // Try to get an open font again - unnamed font. + // See COpenFontFile::GetNearestFontHelper - how it works with unnamed fonts. + actualOpenFontSpec.SetName(KNullDesC); + TRAP(error, GetNearestOpenFontInPixelsL( + openFont, actualOpenFontSpec, desiredFontSpec, aMaxHeight)); + if (KErrNone == error && openFont) + { + aFont = openFont; + return KErrNone; + } + else + { + __ASSERT_DEBUG(false, Panic(EFntNoFontFound)); + return KErrGeneral; + } + } + else if (NULL == openFont) + { + if (actualBitmapFontSpec.Name().CompareF(desiredFontSpec.Name()) != 0) + { + // Try to get the nearest open font - because no exact bitmap font match for typeface name + actualOpenFontSpec.SetName(KNullDesC); + desiredFontSpec.SetName(KNullDesC); + TRAPD(errorOpen, GetNearestOpenFontInPixelsL( + openFont, actualOpenFontSpec, desiredFontSpec, aMaxHeight)); + if (KErrNone == errorOpen && openFont) + { + aFont = openFont; + ReleaseFont(bitmapFont); + } + } + if (aFont == NULL) + { + aFont = bitmapFont; + } + } + else if (NULL == bitmapFont) + { + aFont = openFont; + } + + if (aFont == NULL) + { + // Pick the closest match; for backward compatibility prefer a bitmap font if there is a dead heat. + const TInt open_match = MatchFontSpecsInPixels( + actualOpenFontSpec, desiredFontSpec, openFont->FontMaxHeight(), aMaxHeight); + const TInt bitmap_match = MatchFontSpecsInPixels( + actualBitmapFontSpec, desiredFontSpec, bitmapFont->FontMaxHeight(), aMaxHeight); + if (open_match > bitmap_match) + { + aFont = openFont; + ReleaseFont(bitmapFont); + } + else + { + aFont = bitmapFont; + ReleaseFont(openFont); + } + } + return KErrNone; + } + +/** Gets a bitmap font using the given font UID and algorithmic style. + +Tries to find a bitmap font in the font store with the given UID. If successful, +the given algorithmic style is applied to the font and this font (which may +be a suitable one already existing in the store, or may be a newly generated +font) is stored in aFont. If unsuccessful then no font is stored in aFont. + +@param aFont On return, a device-dependent font. +@param aUid A bitmap font UID. +@param aAlgStyle An algorithmic style to apply to the font. +@return KErrNone if the font is found, KErrNotFound if the font is not found, +or another system-wide error code. */ +EXPORT_C TInt CFontStore::GetFontById( + CFont*& aFont, + TUid aUid, + const TAlgStyle& aAlgStyle) + { + aFont = NULL; + CFontBitmap* fontbitmap = GetFontBitmapById(aUid); + if (!fontbitmap) + { + return KErrNotFound; + } + + const TInt height = fontbitmap->iCellHeightInPixels * aAlgStyle.HeightFactor(); + TFontSpec fontspec; + fontspec.iHeight=height; //Otherwise IsFontLoaded() compares with zero height!!! + fontspec.iTypeface.SetIsProportional(!aAlgStyle.IsMono() && fontbitmap->IsProportional()); + if (aAlgStyle.IsBold() || EStrokeWeightBold == fontbitmap->StrokeWeight()) + { + fontspec.iFontStyle.SetStrokeWeight(EStrokeWeightBold); + } + if (aAlgStyle.IsItalic() || EPostureItalic == fontbitmap->Posture()) + { + fontspec.iFontStyle.SetPosture(EPostureItalic); + } + if (IsFontLoaded(aFont, aAlgStyle, fontspec, fontbitmap->iUid)) + { + return KErrNone; + } + + // Fill in the typeface by finding a typeface with the same font bitmap. + fontspec.iHeight = VerticalPixelsToTwips(height); + const TInt n = iTypefaceFontBitmapList.Count(); + for (TInt i = 0; i < n; i++) + { + if (iTypefaceFontBitmapList[i].iFontBitmap == fontbitmap) + { + fontspec.iTypeface = *iTypefaceFontBitmapList[i].iTypeface; + break; + } + } + TRAPD(ret, aFont = NewFontL(fontspec, aAlgStyle, fontbitmap)); + return ret; + } + +/** Gets the number of typefaces held in the font store. + +Note that this includes both open font typefaces and non-scalable typefaces. + +@return The number of supported typefaces. */ +EXPORT_C TInt CFontStore::NumTypefaces() const + { + return iTypefaceList.Count() + iOpenFontTypefaceSupportList.Count(); + } + +/** Gets a typeface support object for the typeface in the font store represented +by the given index. + +Returns benignly with an empty TTypefaceSupport if the index is too high; +this can happen if another process removes a typeface after the first process +has already got the number of typefaces. However, if the aTypefaceIndex<0 +the function panics with EFntTypefaceIndexOutOfRange. + +@param aTypefaceSupport On return, a typeface support object. +@param aTypefaceIndex An index number representing a typeface, which is valid +if in the range 0 to (NumTypefaces() - 1). */ +EXPORT_C void CFontStore::TypefaceSupport(TTypefaceSupport &aTypefaceSupport,TInt aTypefaceIndex) const + { + if (aTypefaceIndex < 0) + Panic(EFntTypefaceIndexOutOfRange); + + /* + Return benignly with an empty TTypefaceSupport if the index is too high; this can happen if another + process removes a font after the first process has already got the number of typefaces. + */ + int typefaces = NumTypefaces(); + if (aTypefaceIndex >= typefaces) + { + aTypefaceSupport = TTypefaceSupport(); + return; + } + + //now return Typeface Support for Open Fonts + if (aTypefaceIndex >= iTypefaceList.Count()) + { + // copy Open Font typeface details + aTypefaceSupport = *iOpenFontTypefaceSupportList[aTypefaceIndex - iTypefaceList.Count()]->TypefaceSupport(); + return; + } + + __ASSERT_DEBUG((aTypefaceIndex >= 0) && (aTypefaceIndex < iTypefaceList.Count()),Panic(EFntTypefaceIndexOutOfRange)); + TTypeface* typeface = iTypefaceList[aTypefaceIndex]; + aTypefaceSupport.iTypeface = *typeface; + TInt count = iTypefaceFontBitmapList.Count(); + TInt i; + for(i = 0; i < count && iTypefaceFontBitmapList[i].iTypeface != typeface; i++) + { // Finds first fontbitmap with correct typeface + } + aTypefaceSupport.iMinHeightInTwips = VerticalPixelsToTwips(iTypefaceFontBitmapList[i].HeightInPixels()); + aTypefaceSupport.iNumHeights=0; + TInt height=0; + for(; (i= iTypefaceList.Count()) + { + // it's an Open Font managed by a COpenFontFile + if (aTypefaceIndex >= NumTypefaces() || aHeightIndex < 0) + return 0; + + const CTypefaceSupportInfo* supportInfo = iOpenFontTypefaceSupportList[aTypefaceIndex - iTypefaceList.Count()]; + TInt i = Min( supportInfo->NearestPointSizeIndex() + aHeightIndex, + KOpenFontSizeArrayCount - 1); + + return gOpenFontSizeInTwipsArray[i]; + } + else + { + return VerticalPixelsToTwips(FontHeightInPixels(aTypefaceIndex,aHeightIndex)); + } + } + +/** Returns a font height, in pixels, for a certain typeface and height index. + +The font height is a height allowed for the typeface represented by aTypefaceIndex. +The height returned increases with aHeightIndex. + +If aTypefaceIndex<0 the function panics with EFntTypefaceIndexOutOfRange. +If aTypefaceIndex is greater than the number of typefaces or aHeightIndex<0 +then the function returns 0. If aHeightIndex is greater than the number of +heights then the function returns the biggest height. + +@param aTypefaceIndex An index number representing a typeface, which is valid +in the range 0 to (NumTypefaces() - 1). +@param aHeightIndex A font height index number, which is valid in the range +0 to (TTypefaceSupport::iNumHeights - 1). Note that the typeface support object +for the typeface can be got using TypefaceSupport(). +@return The height of a font, in pixels. +@see TypefaceSupport() +*/ +EXPORT_C TInt CFontStore::FontHeightInPixels(TInt aTypefaceIndex,TInt aHeightIndex) const + { + + if (aTypefaceIndex >= iTypefaceList.Count()) // it's an Open Font managed by a COpenFontFile + return VerticalTwipsToPixels(FontHeightInTwips(aTypefaceIndex,aHeightIndex)); + else + { + if (aTypefaceIndex < 0) + Panic(EFntTypefaceIndexOutOfRange); + TTypeface* typeface = iTypefaceList[aTypefaceIndex]; + TInt count = iTypefaceFontBitmapList.Count(); + TInt i; + for(i=0; (i < count) && (iTypefaceFontBitmapList[i].iTypeface != typeface); i++) + { // Finds first fontbitmap with correct typeface + } + TInt height=0,h=0; + for(; (iiFileStore,aFontStoreFile->iDataStreamId); + TInt i, size = stream.ReadInt32L(); + TInt opsPerformed=0; + for (i=0; iAllocL(sizeof(CFontBitmap)); + new(fontbitmap) CFontBitmap(iHeap,aFontStoreFile); + CleanupReleasePushL(*fontbitmap); + fontbitmap->InternalizeL(stream, aFontVersion); + if (GetFontBitmapById(fontbitmap->iUid)) + { + fontbitmap->Release(); + } + else + { + iFontBitmapList.AppendL(fontbitmap); + opsPerformed++; + } + // safely internalized & owned + CleanupStack::Pop(fontbitmap); + } + size = stream.ReadInt32L(); + for (i=0; iInternalizeL(stream); + TInt index,count=iTypefaceList.Count(); + for (index=0; (indexiName.CompareF(iTypefaceList[index]->iName); index++) + { // Looks to see if typeface is already in list + } + if (index == count) // If typeface not in list + { + iTypefaceList.AppendL(typeface); + index = iTypefaceList.Count()-1; + opsPerformed++; + CleanupStack::Pop(); // typeface + } + else + { + CleanupStack::Pop(); // typeface + delete typeface; + typeface=iTypefaceList[index]; + } + TInt num = stream.ReadInt32L(); + for (TInt j=0; j> uid; + CFontBitmap* fontbitmap = GetFontBitmapById(uid); + __ASSERT_DEBUG(fontbitmap,Panic(EFntFontBitmapNotLoaded)); +#ifndef _DEBUG + User::LeaveIfNull(fontbitmap); +#endif + TTypefaceFontBitmap typefacefontbitmap(iTypefaceList[index],fontbitmap); + typefacefontbitmap.iWidthFactor=stream.ReadInt8L(); + typefacefontbitmap.iHeightFactor=stream.ReadInt8L(); + count=iTypefaceFontBitmapList.Count(); + TInt pos; + if (index == count) + { + pos=count; + } + else + { + + for (pos=0; (posPosture()Posture()); pos++) + { // Finds position after fontbitmap with same height + } + for (; (posStrokeWeight()StrokeWeight()); pos++) + { // Finds position after fontbitmap with same height + } + } + TTypefaceFontBitmap* tfbAtPos=(pos==count) + ? NULL + : &iTypefaceFontBitmapList[pos]; + if ( !tfbAtPos + || tfbAtPos->iTypeface!=typeface + || tfbAtPos->HeightInPixels()!=typefacefontbitmap.HeightInPixels() + || tfbAtPos->iFontBitmap->Posture()!=fontbitmap->Posture() + || tfbAtPos->iFontBitmap->StrokeWeight()!=fontbitmap->StrokeWeight() + || tfbAtPos->iWidthFactor!=typefacefontbitmap.iWidthFactor + || tfbAtPos->iHeightFactor!=typefacefontbitmap.iHeightFactor + ) + { + iTypefaceFontBitmapList.InsertL(pos,typefacefontbitmap); + opsPerformed++; + } + } + } + CleanupStack::PopAndDestroy(); // stream + if (!opsPerformed) + User::Leave(KErrAlreadyExists); + } + +TTypeface* CFontStore::GetNearestTypeface(const TTypeface& aTypeface) const + { + TInt index,count = iTypefaceList.Count(); + __ASSERT_DEBUG(count>0,Panic(EFntNoTypefaces)); + for (index=0; (indexiName); index++) + { // tries matching typeface name + } + if (index==count) + { + if (!aTypeface.IsSymbol()) + { + for (index=0; (indexIsSymbol()) || + (aTypeface.IsProportional() != iTypefaceList[index]->IsProportional()) || + (aTypeface.IsSerif() != iTypefaceList[index]->IsSerif())); index++) + { // tries matching typeface flags + } + if (index==count) + for (index=0; (indexIsSymbol()) || + (aTypeface.IsProportional()!=iTypefaceList[index]->IsProportional())); index++) + { // tries matching typeface flags + } + if (index==count) + for (index=0; (indexIsSymbol(); index++) + { // finds first non-symbol typeface + } + } + else + { + for (index=0; (indexIsSymbol()); index++) + { // finds first symbol typeface + } + } + } + + if (index==count) + index=0; + return iTypefaceList[index]; + } + +TTypefaceFontBitmap CFontStore::GetNearestTypefaceFontBitmap(const TFontSpec& aFontSpecInPixels, TInt aMaxHeight) + { + TTypefaceFontBitmap typefacefontbitmap; + TInt count = iTypefaceFontBitmapList.Count(); + __ASSERT_DEBUG(count > 0, Panic(EFntNoTypefaceFontBitmaps)); + TInt i; + TInt j; + // Assumes there is at least one fontbitmap per typeface + for (i = 0; (i < count) && !(aFontSpecInPixels.iTypeface == *iTypefaceFontBitmapList[i].iTypeface); i++) + { // Finds first fontbitmap with correct typeface + } + __ASSERT_DEBUG(i < count, Panic(EFntTypefaceHasNoFontBitmaps)); + TTypeface* typeface = iTypefaceFontBitmapList[i].iTypeface; + TInt height = 0; + if (aMaxHeight > 0) + { // need to check against max height + for (j = i; (j < count) && (iTypefaceFontBitmapList[ j ].iTypeface == typeface) + && (iTypefaceFontBitmapList[j].iFontBitmap->FontMaxHeight() <= aMaxHeight); j++) + { + if (iTypefaceFontBitmapList[j].HeightInPixels() != height) + { + height = iTypefaceFontBitmapList[j].HeightInPixels(); + i = j; + } + } + } + else + { // just check against height + for (j = i; (j < count) && (iTypefaceFontBitmapList[j].iTypeface == typeface) + && (iTypefaceFontBitmapList[j].HeightInPixels() <= aFontSpecInPixels.iHeight); j++) + { + if (iTypefaceFontBitmapList[j].HeightInPixels() != height) + { + height = iTypefaceFontBitmapList[j].HeightInPixels(); + i = j; + } + } + } + for (j = i; (j < count) && (iTypefaceFontBitmapList[j].iTypeface == typeface) + && (iTypefaceFontBitmapList[j].HeightInPixels() == height); j++) + { // Finds position after fontbitmap correct posture + if ((iTypefaceFontBitmapList[j].iFontBitmap->Posture() <= aFontSpecInPixels.iFontStyle.Posture()) && + (iTypefaceFontBitmapList[j].iFontBitmap->StrokeWeight() <= aFontSpecInPixels.iFontStyle.StrokeWeight())) + i = j; + } + typefacefontbitmap = iTypefaceFontBitmapList[i]; + return typefacefontbitmap; + } + +CFontBitmap* CFontStore::GetFontBitmapById(TUid aUid) + { + CFontBitmap* fontbitmap = NULL; + TInt i, count = iFontBitmapList.Count(); + for (i = 0; (i < count) && (aUid != iFontBitmapList[i]->iUid); i++) + { // finds matching font bitmap + } + if (iFontMaxHeight(); } +static TInt GetHeightShimHeightPixels(CFont* aFont) { return aFont->HeightInPixels(); } + +/** +Font spec comparison is based on +1. Max height if its given, otherwise design height +2. All other attributes in TFontSpec + +@see CFbsTypefaceStore::IsFontLoaded +@see CPdrTypefaceStore::IsFontLoaded +*/ +TBool CFontStore::IsFontLoaded( + CFont*& aFont, + const TAlgStyle& aAlgStyle, + const TFontSpec& aFontSpecInPixels, + TUid aUid, + TInt aMaxHeight) const + { //It is not worth copying iFontAccess to frame as it doesn't get register optimised. + const TInt count = iFontAccess->Count(); + const TInt reqHeight = aMaxHeight ? aMaxHeight : aFontSpecInPixels.iHeight; + TInt (*heightFn)(CFont*) = aMaxHeight ? GetHeightShimMaxHeight : GetHeightShimHeightPixels; + for (TInt i = 0; i < count; i++) + { + CBitmapFont* bitmapFont = reinterpret_cast((*iFontAccess)[i].iFont); + if (bitmapFont->Uid() != aUid || + bitmapFont->iAlgStyle != aAlgStyle || + heightFn(bitmapFont) != reqHeight + ) + { + continue; + } + TFontSpec fontSpec = bitmapFont->FontSpecInTwips(); + if ( fontSpec.iFontStyle == aFontSpecInPixels.iFontStyle && + fontSpec.iTypeface.iName == aFontSpecInPixels.iTypeface.iName + ) + { + (*iFontAccess)[i].iAccessCount++; + aFont = static_cast(bitmapFont); + return ETrue; + } + } + return EFalse; + } + +CBitmapFont* CFontStore::NewFontL( + const TFontSpec& aFontSpecInTwips, + const TAlgStyle& aAlgStyle, + CFontBitmap* aFontBitmap) + { + CBitmapFont* f = CBitmapFont::NewL(iHeap, aFontSpecInTwips, aAlgStyle, aFontBitmap); + CleanupStack::PushL(f); + AddFontL(f); + CleanupStack::Pop(); + f->SetUniqueFontId(++iUniqueFontIdCount); + return f; + } + +CBitmapFont* CFontStore::NewFontL( + const TOpenFontSpec& aFontSpecInTwips, + const TAlgStyle& aAlgStyle, + COpenFont* aOpenFont) + { + TFontSpec spec; + aFontSpecInTwips.GetTFontSpec(spec); + CBitmapFont* f = CBitmapFont::NewL(iHeap, spec, aAlgStyle, aOpenFont); + CleanupStack::PushL(f); + AddFontL(f); + CleanupStack::Pop(); + f->SetUniqueFontId(++iUniqueFontIdCount); + return f; + } + +// This function is biased towards rounding up +// The cutoff is effectively at one-third of a pixel +// This is to match VerticalTwipsToPixels(...) +TInt CFontStore::VerticalPixelsToTwips(TInt aPixelHeight) const + { + return ((aPixelHeight * iKPixelHeightInTwips) + 667) / 1000; // Rounds up above one-third of a pixel + } + +// This function is biased towards rounding down +// The cutoff is effectively at two-thirds of a twip +// This is to support the legacy system of rounding down +// but with a sanity-check cutoff to round up past two-thirds +TInt CFontStore::VerticalTwipsToPixels(TInt aTwipsHeight) const + { + __ASSERT_DEBUG(iKPixelHeightInTwips,Panic(EFntKPixelHeightInTwipsZero)); + return ((aTwipsHeight * 1000) + (iKPixelHeightInTwips / 3)) / iKPixelHeightInTwips; // Rounds down below two-thirds of a twip + } + +/** Installs and takes ownership of an Open Font rasterizer. + +@param aRasterizer A pointer to an Open Font rasterizer. */ +EXPORT_C void CFontStore::InstallRasterizerL(COpenFontRasterizer* aRasterizer) + { + iOpenFontRasterizerList.AppendL(aRasterizer); + } + +/** Install and takes ownership of the shaper + +@param aShaperFactory A pointer to a shaper factory. */ +EXPORT_C void CFontStore::InstallShaperFactoryL(CShaperFactory* aShaperFactory) + { + iShaperFactoryList.AppendL(aShaperFactory); + } + +/** Deletes the glyph cache belonging to a particular client. + +Called by ~CFbClient(). + +@param aSessionHandle A session handle. */ +EXPORT_C void CFontStore::DeleteSessionCache(TInt aSessionHandle) + { + iOpenFontSessionCacheList->DeleteCache(iHeap,aSessionHandle); + } + +const CArrayPtrFlat* CFontStore::ShaperFactoryList() const + { + return &iShaperFactoryList; + } + +/** Returns the list of session caches owned by the COpenFonts +@internalComponent */ +COpenFontSessionCacheList* CFontStore::GetSessionCacheList() + { + return iOpenFontSessionCacheList; + } + +/** Returns the total cache memory used by all the COpenFonts in the system + @return Total cache memory usage + @internalComponent +*/ +TInt CFontStore::GetShaperCacheMemUsage() + { + return iOpenFontShaperCacheMemUsage; + } + +/** Updates the total cache memory used by all the COpenFonts in the system + @param aUsage New value of total cache memory usage + @internalComponent +*/ +void CFontStore::SetShaperCacheMemUsage(TInt aUsage) + { + iOpenFontShaperCacheMemUsage = aUsage; + } + +/** Returns the list of COpenFontFiles owned by the CFontStore object + @internalComponent +*/ +CArrayPtrFlat* CFontStore::GetOpenFontFileList() + { + return &iOpenFontFileList; + } + +void CFontStore::IncNumShaperCaches() + { + iNumberOfShaperCaches++; + } + +void CFontStore::DecNumShaperCaches() + { + iNumberOfShaperCaches--; + } + +TInt CFontStore::GetNumShaperCaches() + { + return iNumberOfShaperCaches; + } + + +/** Adds the typeface( of the currently added openfont file from the store) to Open Font System typefaces Supported List +ignoring duplicate family names. +1. Prior to adding the entry into the typefaceList, it is searched whether already exists or not +2. If it is found only its reference count is incremented. +3. If it is not found then its reference count is set to 1 and added that entry into the typefacelist. +4. If 0 typefaces are added then KErrAlreadyExists is returned causing the new font to be unloaded. +@return KErrNone is successful, otherwise a system wide error code +@internalComponent +*/ +TInt CFontStore::AddTypefacesToSupportList(COpenFontFile* aOpenFontFile) + { + TInt faceCount = aOpenFontFile->FaceCount(); + CTypefaceSupportInfo* typefaceFamily = NULL; + TInt error = KErrNone; + TBool facesAdded=0; + // go through all fonts, stop early if an error + for (TInt faceIndex = 0; (faceIndex < faceCount) && (error == KErrNone); ++faceIndex) + { + //Preparing the Supported Typeface Entry + if (typefaceFamily == NULL) + { // need a new typeface object + typefaceFamily = new CTypefaceSupportInfo(); + if (typefaceFamily == NULL) + { // failed + error = KErrNoMemory; + break; + } + } + + // initialise for next type face + const TOpenFontFaceAttrib& faceAttrib = aOpenFontFile->FaceAttrib(faceIndex); + typefaceFamily->SetTypefaceInfo(faceAttrib, VerticalPixelsToTwips(faceAttrib.MinSizeInPixels())); + + TInt fontPos = -1; // an invalid index + TInt findError = iOpenFontTypefaceSupportList.FindInOrder(typefaceFamily, fontPos, CTypefaceSupportInfo::CompareFontNames); + + // new font family? + if (findError == KErrNotFound) + { + // back reference to the font file + error = typefaceFamily->AddFontFilePtr(aOpenFontFile); + if (error == KErrNone) + { // transfer ownership + error = iOpenFontTypefaceSupportList.Insert(typefaceFamily, fontPos); + if (error == KErrNone) + { + typefaceFamily = NULL; + facesAdded++; + } + } + } + else + { + // back reference to the new font file (allowed to fail with KErrAlreadyExists) + TInt addError = iOpenFontTypefaceSupportList[fontPos]->AddUniqueFontFilePtr(aOpenFontFile,faceAttrib); + if (addError==KErrNone) + { + facesAdded++; + } + else if (addError == KErrInUse ) + { + //remove typeface from loaded font file???? + } + else if (addError != KErrAlreadyExists ) + { + error = addError; + } + //else KErrAlreadyExists because loaded by a lower-indexed face in this font file, so faces won't be zero. + } + } + + if (typefaceFamily != NULL) + { + delete typefaceFamily; + } + if (facesAdded==0 && error==KErrNone) + { + error= KErrAlreadyExists; + } +#ifdef _DEBUG + // check that array is in order + const TInt countTypefaceFamilies = iOpenFontTypefaceSupportList.Count(); + for (TInt fontPos = 0; fontPos < countTypefaceFamilies - 1; ++fontPos) + { + TInt cmp = CTypefaceSupportInfo::CompareFontNames(*iOpenFontTypefaceSupportList[fontPos], *iOpenFontTypefaceSupportList[fontPos+1]); + ASSERT(cmp < 0); + } +#endif + + return error; + } + + +/** Removes the typefaces from the Support List corresponding to the fontfile removed from + the fontstore +This is done by +1. Searching in the typefacesupportList for pointer references to the font file. +2. If the file is referenced by the typeface family remove the reference. +3. If typeface family no has any implementations remove the family +@internalComponent +*/ +void CFontStore::RemoveTypefacesFromSupportList(COpenFontFile* aOpenFontFile) + { + const TInt countTypefaceFamilies = iOpenFontTypefaceSupportList.Count(); + + // search typeface families + for (TInt fontPos = countTypefaceFamilies - 1; fontPos >= 0; --fontPos) + { + CTypefaceSupportInfo* fontInfo = iOpenFontTypefaceSupportList[fontPos]; + + // look for back pointer to this Font File + TInt fontFileIndex = fontInfo->FindFontFilePtr(aOpenFontFile); + + if (fontFileIndex > KErrNotFound) + { // remove pointer + if (fontInfo->RemoveFontFilePtr(fontFileIndex)) + { // last implementation of the family, so delete it + delete fontInfo; + iOpenFontTypefaceSupportList.Remove(fontPos); + } + } + } + } + +/** +This function checks the supplied typeface name against the existing bitmap and open +typefaces, to see if it present. + +@param aName The name of the typeface family name to be checked. +@return ETrue if the typeface is present, EFalse otherwise. + +@released +@internalTechnology +*/ +EXPORT_C TBool CFontStore::HaveTypefaceFamilyName(const TDesC& aName) + { + //there are two lists for typefaces + //not supporting linked fonts here + + //first list is open fonts + TInt count = iOpenFontTypefaceSupportList.Count(); + for (TInt index=count-1;index>=0;index--) + { + if (aName.CompareF(iOpenFontTypefaceSupportList[index]->iSupport.iTypeface.iName)==0) + return ETrue; + } + + //now look through bitmap fonts + count = iTypefaceList.Count(); + for (TInt index=count-1;index>=0;index--) + { + if (aName.CompareF(iTypefaceList[index]->iName)==0) + return ETrue; + } + + return EFalse; + } + +/** +@internalTechnology +@released +*/ +EXPORT_C TInt CFontStore::CreateLinkedTypeface(const TLinkedTypefaceSpecificationArgs &aLinkedTypefaceSpec, TInt aSession, TInt& aId) + { + TInt err; + TInt retErr=0; + TRAP(err,retErr = CreateLinkedTypefaceL(aLinkedTypefaceSpec,aSession,aId)); + if (err!=KErrNone) + { + return err; + } + else + { + return retErr; + } + } + +/* this function is used to create the linked typeface, the linked typeface is created on + * the font and bitmap server heap, not the shared heap. + */ +TInt CFontStore::CreateLinkedTypefaceL(const TLinkedTypefaceSpecificationArgs &aLinkedTypefaceSpec, TInt /*aSession*/, TInt& /*aId*/) + //reconstuct a CLinkedTypefaceSpecification - could store as T type, but then the + // maximum size would be used for every linked typeface + // + { + const TAny* extensionPtr = FontLinkingInterface(); + + if (extensionPtr == NULL) + return KErrNotSupported; + + //Convert the TLinkedTypefaceSpecification args into the + //COpenFontLinkedTypefaceSpecification recognised by the rasteriser + COpenFontLinkedTypefaceSpecification* spec = + COpenFontLinkedTypefaceSpecification::NewLC(aLinkedTypefaceSpec); + + TInt err = ValidateLinkedFontSpecificationL(*spec, EFalse); + + if (err == KErrNone) + { + GenerateLinkedFontFileL(*spec, extensionPtr, EFalse); + } + + CleanupStack::PopAndDestroy(spec); + return err; + } + +/* +@internalTechnology +Retrieve the specification from a linked typeface; the name of the typeface should be specified in the parameter. + +@param aLinkedTypefaceSpec An empty linked typeface spec containing the name of the typeface to be retrieved. + +@leave One of the system wide error codes. +*/ +EXPORT_C void CFontStore::GetLinkedTypefaceL(TLinkedTypefaceSpecificationArgs &aLinkedTypefaceSpec) + { + const TAny* extensionPtr = FontLinkingInterface(); + + if (extensionPtr == NULL) + User::Leave(KErrNotSupported); + + MOpenFontLinkedTypefaceExtension* linkedExt = (MOpenFontLinkedTypefaceExtension*)extensionPtr; + + //Check whether the font is loaded + CTypefaceSupportInfo* supinfo; + TTypefaceSupport support; + COpenFontFile* fetchFont=NULL; + for (TInt count=0;count<(iOpenFontTypefaceSupportList.Count());count++) + { + supinfo = iOpenFontTypefaceSupportList[count]; + support = supinfo->iSupport; + + if (aLinkedTypefaceSpec.iName==support.iTypeface.iName) + { + fetchFont = supinfo->iOpenFontFilePtrArray[0]; + + break; + } + } + if (fetchFont==NULL) + { + User::Leave(KErrNotFound); + } + + COpenFontLinkedTypefaceSpecification* typefaceSpec = COpenFontLinkedTypefaceSpecification::NewLC(aLinkedTypefaceSpec.iName); + TFileName fetchFile = fetchFont->FileName(); + linkedExt->GetLinkedTypefaceSpecificationL(fetchFile, *typefaceSpec); + aLinkedTypefaceSpec = *typefaceSpec; + CleanupStack::PopAndDestroy(typefaceSpec); + } + +/* +@internalTechnology +Updates an existing linked typeface to a new specification. + +@param aLinkedTypefaceSpec The new specification for the typeface + +@leave KErrNotSupported Font linking is not supported by any of the installed rasterizers +@leave One of the system wide error codes. +*/ +EXPORT_C void CFontStore::UpdateLinkedTypefaceL(const TLinkedTypefaceSpecificationArgs& aLinkedTypefaceSpec) + { + const TAny* extensionPtr = FontLinkingInterface(); + + if (extensionPtr == NULL) + User::Leave(KErrNotSupported); + + //Convert the TLinkedTypefaceSpecification args into the + //COpenFontLinkedTypefaceSpecification recognised by the rasteriser + COpenFontLinkedTypefaceSpecification* spec = + COpenFontLinkedTypefaceSpecification::NewLC(aLinkedTypefaceSpec); + + TInt err = ValidateLinkedFontSpecificationL(*spec, ETrue); + User::LeaveIfError(err); + + GenerateLinkedFontFileL(*spec, extensionPtr, ETrue); + + CleanupStack::PopAndDestroy(spec); + } + +/** +@internalTechnology +Performs the loading of font files at boot time. This is a three stage procedure. + +1. Copies linked fonts to be updated from their temporary directory into the linked fonts folder +2. Loads all the linked fonts from the linked fonts folder. +3. Loads all remaining font files from *:\resource\fonts + */ +EXPORT_C void CFontStore::LoadFontsAtStartupL() + { + //First copy any updated linked fonts from their temporary dir to the linked font dir + CFileMan* fm = CFileMan::NewL(iFs); + CleanupStack::PushL(fm); + + //Get the fbserv private folder + TBuf privPath; + iFs.PrivatePath(privPath); + + //Construct the linked font dir path + TBuf linkedFontDir; + linkedFontDir.Format(KLinkedFontFileFolder, KLinkedFontDrive, &privPath); + + //Construct the linked font temp dir path + TBuf linkedFontTempDir; + linkedFontTempDir.Append(linkedFontDir); + linkedFontTempDir.Append(KLinkedFontFileTempFolder); + + //Copy the temp folder into the main folder + TInt err = fm->Copy(linkedFontTempDir, linkedFontDir, CFileMan::EOverWrite); + + if (err == KErrNone) + { + //If sucessful copying remove the temp folder + //A leave is not thrown as the empty directory remaining is not a significant enough + //to prevent fbserv from starting + fm->RmDir(linkedFontTempDir); + } + + CleanupStack::PopAndDestroy(fm); + + //Load Linked Fonts + LoadFontsL(linkedFontDir); + + //Load the remaining fonts + LoadFontsL(KFBSERVFontDirSecure); + } +/** +@internalTechnology +Returns the pointer to the first rasterizer supporting font linking (KUidLinkedTypefaceRasterizerExtension). +*/ +const TAny* CFontStore::FontLinkingInterface() const + { + TInt rastcount = iOpenFontRasterizerList.Count(); + COpenFontRasterizer* rast; + TAny* extensionPtr = NULL; + + //Check each rasterizer in turn to check it supports the extended interface. + //In reality there should only be one but multiple rasterizers are supported. + for (TInt i = 0 ; i != rastcount ; i++) + { + rast = iOpenFontRasterizerList[i]; + rast->ExtendedInterface(KUidLinkedTypefaceRasterizerExtension, extensionPtr); + + if (extensionPtr != NULL) + break; + } + + return extensionPtr; + } + +/** +Validates the linked font specification passed as a parameter. + +@param aSpec The specification to be validated +@param aOverwrite ETrue if this is an update operation, EFalse otherwise +*/ +TInt CFontStore::ValidateLinkedFontSpecificationL(COpenFontLinkedTypefaceSpecification& aSpec, TBool aOverwrite) const + { + //see if the typeface is an existing regular typeface. + if (!aOverwrite) + { + TInt numberTypefaces = iTypefaceList.Count(); + TInt c; + + for (c=0;ciName.CompareF(aSpec.Name())) + { + //A typeface with this name is already loaded + return KErrAlreadyExists; + } + } + + TInt numberOpenFontFiles = iOpenFontFileList.Count(); + for (c=0;cFaceCount(); + TInt c2; + for (c2=0;c2FaceAttrib(c2); + + /* only comparing on the name */ + if (0== attrib.ShortFullName().CompareF(aSpec.Name())) + { + //have a matching name, return error + return KErrAlreadyExists; + } + if (0== attrib.ShortFamilyName().CompareF(aSpec.Name())) + { + //have a matching name, return error + return KErrAlreadyExists; + } + } + } + } + //For each element, check whether the typeface exists and add the correct filename to the spec if it does + TInt numTypefaces = aSpec.TypefaceCount(); + TFileName fileName; + COpenFontLinkedTypefaceElementSpec* element; + + for (TInt counter=0;counterElementName(), fileName)) + { + element->SetFileNameL(fileName); + } + else + { + return KErrNotFound; + } + } + return KErrNone; + } + + +/** +Sends the specification to the font rasterizer to be created/updated. + +@param aSpec The linked font specification +@param aExtension The extension interface of the chosen rasterizer +@param aUpdate ETrue if the file is being updated, EFalse if it should be created + +@leave KErrNotFound Attempting to update a file which does not exist + */ +void CFontStore::GenerateLinkedFontFileL(COpenFontLinkedTypefaceSpecification& aSpec, const TAny* aExtension, TBool aUpdate) + { + MOpenFontLinkedTypefaceExtension* linkedExt = (MOpenFontLinkedTypefaceExtension*)aExtension; + + //Generate the filename for the linked font file (excluding the extension + //and the .) which are appended by the rasterizer. + TFileName privPath; + User::LeaveIfError(iFs.PrivatePath(privPath)); + TFileName fn; + fn.Format(KLinkedFontFileFolder, KLinkedFontDrive, &privPath); + + //Choose the correct path to write the file to + if (aUpdate) + { + fn.Append(KLinkedFontFileTempFolder); + } + + // Create the directory if it does not exist + TInt result = iFs.MkDirAll(fn); + if (result != KErrAlreadyExists) + { + User::LeaveIfError(result); + } + + //Append the linked font filename to the path for the rasterizer. + fn.Append(aSpec.Name()); + + // If we are updating, check that the file is a linked typeface before attempting the update. + if (aUpdate) + { + TFileName fn; + TBool exists = GetFontFilePath(aSpec.Name(), fn); + + if (exists) + { + COpenFontLinkedTypefaceSpecification* tempSpec = COpenFontLinkedTypefaceSpecification::NewLC(aSpec.Name()); + TRAPD(ret, linkedExt->GetLinkedTypefaceSpecificationL(fn, *tempSpec)); + User::LeaveIfError(ret); + CleanupStack::PopAndDestroy(tempSpec); + } + else + { + User::Leave(KErrNotFound); + } + } + + //Use the rasterizer extension to create the linked typeface + linkedExt->CreateLinkedTypefaceL(aSpec, fn); + + // Load the new linked typeface + if (!aUpdate) + { + AddFileL(fn); + } + } + +/** +Function called at system startup to find and load all fonts in the specified +folder. The value of the folder will be the secure Data-caged private folder +named "\resource\fonts". + +The first font of a given name overrides subsequent ones. + +The search order is: Y:, X:, W:, ..., C:, B:, A:, Z: + +@see TFindFile +@param aFontsDir The directory search pattern + */ +void CFontStore::LoadFontsL(const TDesC& aFontsDir) + { +#ifdef _DEBUG + _LIT(KLoadStarted, "CFontStore::LoadFontsL Started.\r\n"); + RDebug::Print(KLoadStarted); + TUint32 loadStartTime = StartTiming(); +#endif + + RArray fontsToLoad; + CleanupClosePushL(fontsToLoad); + TFindFile fileFinder(iFs); + CDir* foundFileList = NULL; + + _LIT(KFBSERVFontFilePattern, "*"); + TInt findFileComplete = fileFinder.FindWildByDir(KFBSERVFontFilePattern, aFontsDir, foundFileList); + + while (!findFileComplete) + { + CleanupStack::PushL(foundFileList); + const TInt foundFileCount = foundFileList->Count(); + const TDesC& pathInfo = fileFinder.File(); + + // Build a list of fonts to be loaded eliminating duplicate filenames. + for (TInt ii = 0; ii < foundFileCount; ii++) + { + TParse fullFontFileName; + if (fullFontFileName.Set((*foundFileList)[ii].iName, &pathInfo, NULL) == KErrNone) + { + // If the font has not already been loaded, validate it then add it to the list. + if (!FileIsInList(fullFontFileName, fontsToLoad)) + { + // Do not validate fonts on Z: (assumed to be ROM created with valid fonts) + if (FileIsOnZ(fullFontFileName)) + { + fontsToLoad.AppendL(fullFontFileName); + } + else + { + // Test font before loading + TRAPD(err, SanityCheckFontFileL(fullFontFileName)) + if (KErrNone == err) + { + // Add file + fontsToLoad.AppendL(fullFontFileName); + } + else + { + _LIT(KCorruptFont, "CFontStore::LoadFontsL %S could not be loaded.\r\n"); + RDebug::Print(KCorruptFont, &fullFontFileName.FullName()); + } + } + } + } + } + + CleanupStack::PopAndDestroy(foundFileList); + findFileComplete = fileFinder.FindWild(foundFileList); + } + + // Load the fonts in reverse order (i.e. Z:, A: to Y:) this causes + // fonts on Z: to take priority over fonts on A: to Y: when the internal + // font names are identical. + TInt kk = fontsToLoad.Count(); + while(kk--) + { + TUid fontUid = KNullUid; + + // Load this font as a new font, and add it to the list of loaded fonts + TRAPD(addFileError, AddSanityCheckedFontL(fontsToLoad[kk], fontUid)); + if (addFileError) + { + _LIT(KLoadedFont, "CFontStore::LoadFontsL failed with error %i to load font, filename: %S\r\n"); + RDebug::Print(KLoadedFont, addFileError, &(fontsToLoad[kk].FullName())); + } +#ifdef _DEBUG + else + { + // NOTE: This is to make testing of confirming what fonts are loaded a little easier as there is no + // easy way to get this information from outside the server. + _LIT(KLoadedFont, "CFontStore::LoadFontsL loaded font filename: %S\r\n"); + RDebug::Print(KLoadedFont, &(fontsToLoad[kk].FullName())); + } +#endif + } + +#ifdef _DEBUG + TUint32 loadTime = FinishTimingL(loadStartTime); + _LIT(KLoadEnded, "CFontStore::LoadFontsL Finished. Took: %dus\r\n"); + RDebug::Print(KLoadEnded, loadTime); +#endif + CleanupStack::PopAndDestroy(&fontsToLoad); + } +/** +Retrieves the full path and filename of the font with the specified name. This function +searches through all open font files currently loaded by font store. + +@param aFontName The full name of the font to search for +@param aFilePath An empty descriptor to have the file name filled in + +@return ETrue if the font is found; EFalse if not +*/ +EXPORT_C TBool CFontStore::GetFontFilePath(const TDesC& aFontName, TFileName& aFilePath) const + { + TInt numTypefaces = iOpenFontFileList.Count(); + COpenFontFile* thisFile; + TOpenFontFaceAttrib faceAttrib; + + //For every (Truetype) font file + for (TInt i = 0 ; i != numTypefaces ; i++) + { + thisFile = iOpenFontFileList[i]; + + //For every face within this file + for (TInt face = 0 ; face != thisFile->FaceCount() ; face++) + { + faceAttrib = thisFile->FaceAttrib(face); + if (faceAttrib.FullName().CompareF(aFontName) == 0) + { + aFilePath = thisFile->FileName(); + return ETrue; + } + } + } + return EFalse; + } + +TInt CFontStore::CacheFontTable(TUid aFileUid, TUint32 aTag, + TAny *&aContent, TInt aLength) + { + return iFontTableCache->Append(aFileUid, aTag, aContent, aLength); + } + +TInt CFontStore::FindFontTableInCache(TUid aFileUid, TUint32 aTag, + TAny *&aContent, TInt &aLength) + { + TInt id; + return iFontTableCache->Find(aFileUid, aTag, aContent, aLength, &id); + } + +TInt CFontStore::IncreaseUnhintedOutlineRefCount(const TUnhintedOutlineId &aOutlineId, + TInt aSessionHandle) + { + return iUnhintedOutlineCache->IncRefCount(aOutlineId, aSessionHandle); + } + +TInt CFontStore::IncreaseHintedOutlineRefCount(const THintedOutlineId &aOutlineId, + TInt aSessionHandle) + { + return iHintedOutlineCache->IncRefCount(aOutlineId, aSessionHandle); + } + +TInt CFontStore::IncFontTableRefCount(TUid aFileUid, TUint32 aTag, + TInt aSessionHandle) + { + return iFontTableCache->IncRefCount(aFileUid, aTag, aSessionHandle); + } + +TInt CFontStore::DecFontTableRefCount(TUid aFileUid, TUint32 aTag, + TInt aSessionHandle) + { + return iFontTableCache->DecRefCount(aFileUid, aTag, aSessionHandle); + } + +TInt CFontStore::CacheUnhintedOutline(const TUnhintedOutlineId &aOutlineId, TAny * aData, + TInt aLength, TAny *&aOutline, TInt &aLen) + { + return iUnhintedOutlineCache->CacheUnhintedOutline(aOutlineId, aData, aLength, + aOutline, aLen); + } + +TInt CFontStore::CacheHintedOutline(const THintedOutlineId &aOutlineId, + TAny * aData, TInt aLength, TAny *&aOutline, TInt &aLen) + { + return iHintedOutlineCache->CacheHintedOutline(aOutlineId, aData, aLength, + aOutline, aLen); + } + +TInt CFontStore::ReleaseUnhintedOutline(const TUnhintedOutlineId &aOutlineId, + TInt aSessionHandle) + { + return iUnhintedOutlineCache->DecRefCount(aOutlineId, aSessionHandle); + } + +TInt CFontStore::ReleaseHintedOutline(const THintedOutlineId &aOutlineId, + TInt aSessionHandle) + { + return iHintedOutlineCache->DecRefCount(aOutlineId, aSessionHandle); + } + +TInt CFontStore::ReleaseFontTable(TUid aFileUid, TUint32 aTag, + TInt aSessionHandle) + { + return iFontTableCache->DecRefCount(aFileUid, aTag, aSessionHandle); + } + +TInt CFontStore::FindUnhintedOutlineInCache(const TUnhintedOutlineId &aOutlineId, TAny *&aData, + TInt &aLength) + { + return iUnhintedOutlineCache->Find(aOutlineId, aData, aLength); + } + +TInt CFontStore::FindHintedOutlineInCache(const THintedOutlineId &aOutlineId, + TAny *&aData, TInt &aLength) + { + return iHintedOutlineCache->Find(aOutlineId, aData, aLength); + } + +void CFontStore::CleanupCacheOnOpenFontRemoval(COpenFont *aFont) + { + iHintedOutlineCache->CleanupCacheOnOpenFontRemoval(aFont); + //iUnhintedOutlineCache.OnOpenFontRemoval(aFont); + } + +void CFontStore::CleanupCacheOnOpenFontFileRemoval(COpenFontFile *aFontFile) + { + iUnhintedOutlineCache->CleanupCacheOnOpenFontFileRemoval(aFontFile); + iFontTableCache->CleanupCacheOnOpenFontFileRemoval(aFontFile); + } + +/** Clean up font table and glyph outline caches when an FBS session is terminated. + * All the reference counts related to that session are cleared. +@param aSession: Input. A pointer to the terminating session. +@return always returns KErrNone. +@internalTechnology +*/ +EXPORT_C +void CFontStore::CleanupCacheOnFbsSessionTermination(TInt aSessionHandle) + { + iHintedOutlineCache->CleanupCacheOnFbsSessionTermination(aSessionHandle); + iUnhintedOutlineCache->CleanupCacheOnFbsSessionTermination(aSessionHandle); + iFontTableCache->CleanupCacheOnFbsSessionTermination(aSessionHandle); + } + + +void TFontTableGlyphOutlineCacheMemMonitor::Inc(TInt aBytes) + { + iBytes += aBytes; + } + +void TFontTableGlyphOutlineCacheMemMonitor::Dec(TInt aBytes) + { + iBytes -= aBytes; + } + +TInt TFontTableGlyphOutlineCacheMemMonitor::GetMemUsage() + { + return iBytes; + } + +TFontTableGlyphOutlineCacheMemMonitor::TFontTableGlyphOutlineCacheMemMonitor(): + iBytes(0) + { + // null constructor + } + +TUnhintedOutlineId::TUnhintedOutlineId(TUid aFileUid, TInt aFaceIndex, TUint aId): +iFileUid(aFileUid), iFaceIndex(aFaceIndex), iId(aId) + { + // a null constructor; + } + +THintedOutlineId::THintedOutlineId(COpenFont *aFont, TUint aId): +iFont(aFont), iId(aId) + { + // a null constructor; + } + +#ifdef _DEBUG +/** +Returns a timestamp for use by FinishTimingL(). +@return The timestamp. +@see FinishTimingL +*/ +TUint32 StartTiming(void) + { + return User::FastCounter(); + } + +/** +Returns the time difference between a given time and now in microseconds. +@param aStartTime The start time returned by calling StartTiming() +@return The time difference in microseconds. +@see StartTiming() +*/ +TUint32 FinishTimingL(TUint32 aStartTime) + { + TInt freq = 0; + TUint32 endtime = User::FastCounter(); + User::LeaveIfError(HAL::Get(HALData::EFastCounterFrequency, freq)); + TUint32 diff = endtime - aStartTime; + TInt64 diffTime = (1000000 * TInt64(diff)) / (TInt64)freq; + return TUint32(diffTime); + } +#endif + +/** +Returns true if the filename passed in is on the Z: drive +@param aFileName The filename to check +@return ETrue if the file is on Z: +*/ +TBool FileIsOnZ(TParse& aFileName) + { + TBool onZ = EFalse; + + const TDesC& fileDrive = aFileName.Drive(); + _LIT(KZDrive,"z:"); + if (0 == fileDrive.CompareF(KZDrive)) + { + onZ = ETrue; + } + + return onZ; + } + + +/** +Returns true if the filename passed in is in the supplied list +@param aFileName The filename to check +@param aList The list to check +@return ETrue if the file is in the list +*/ +TBool FileIsInList(TParse& aFileName, RArray& aList) + { + TBool inList = EFalse; + + TInt jj = aList.Count(); + while(jj--) + { + TPtrC shortFilename = aFileName.NameAndExt(); + if (shortFilename.CompareF( aList[jj].NameAndExt() ) == 0) + { +#ifdef _DEBUG + _LIT(KEclipsesFont, "CFontStore::FileIsInList %S eclipses %S\r\n"); + RDebug::Print(KEclipsesFont, &aList[jj].FullName(), &aFileName.FullName()); +#endif + inList = ETrue; + break; + } + } + + return inList; + }