graphicsdeviceinterface/directgdiadaptation/hwsrc/glyphimagecache.cpp
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graphicsdeviceinterface/directgdiadaptation/hwsrc/glyphimagecache.cpp	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,1055 @@
+// Copyright (c) 2007-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 "glyphimagecache.h"
+#include "glyphlutab.h"
+#include "vgengine.h"
+#include <fbs.h>
+
+//the image of the following size will be pre-allocated for low memory conditions.
+const TSize KMaxSizeImageOOM(72, 64);
+#ifdef DRAWGLYPH_MULTIPLY_MODE
+// Matrix used for converting glyphs with a background colour of black and a character colour
+// of white to have a background colour that is fully transparent black and a character colour
+// of opaque black. 
+const VGfloat KColorMatrix[20] = { 0, 0, 0, 1, // sets alpha of destination to R value of source
+				                   0, 0, 0, 0,
+				                   0, 0, 0, 0,
+				                   0, 0, 0, 0,
+				                   1, 1, 1, 0}; // sets RGB of destination to 1
+#endif // DRAWGLYPH_MULTIPLY_MODE
+
+//--------------class CFontGlyphTree --------------------
+/**
+Creates a new instance of the class. Will not be shared across different threads 
+
+@param 	aFontId The unique font identifier.
+@param 	aGlyphType The type for the format of a glyph bitmap.
+@return The pointer to the CFontGlyphTree class instance.
+ */
+CFontGlyphTree* CFontGlyphTree::NewL(TUint32 aFontId, TGlyphBitmapType aGlyphType)
+	{
+	CFontGlyphTree*  self = new (ELeave) CFontGlyphTree(aFontId, aGlyphType);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+/**
+Constructor for the image font glyph tree
+
+@param 	aFontId The unique font identifier.
+@param 	aGlyphType The type for the format of a glyph bitmap.
+*/
+CFontGlyphTree::CFontGlyphTree(TUint32 aFontId, TGlyphBitmapType aGlyphType) :
+	iKey(_FOFF(TGlyphEntry,iGlyphCode),ECmpTUint32),
+	iFontId(aFontId),
+	iGlyphType(aGlyphType)
+	{
+	}
+	
+/**
+Destructor for the image font glyph tree.
+
+Destroys the VGImages, page pool and binary tree. 
+*/
+CFontGlyphTree::~CFontGlyphTree()
+	{
+	TRAP_IGNORE(DestroyAllVGImagesL());
+	delete iGlyphTree;
+	delete iPagePool;
+	}
+	
+/**
+Constructs memory page pool and binary tree. Glyph code will be used as a key.
+*/
+void CFontGlyphTree::ConstructL()
+	{
+	iPagePool = CMemPagePool::NewL();
+	
+	switch(iGlyphType)
+		{
+	case EFourColourBlendGlyphBitmap:
+		iGlyphTree = new (ELeave) TBtreeFix<TGlyphEntryCompound, TChar> (EBtreeFast);
+		((TBtreeFix<TGlyphEntryCompound, TChar> *)iGlyphTree) -> Connect(iPagePool, &iKey);
+		break;
+	case EMonochromeGlyphBitmap:
+	case EAntiAliasedGlyphBitmap:
+		iGlyphTree = new (ELeave) TBtreeFix<TGlyphEntry, TChar> (EBtreeFast);
+		((TBtreeFix<TGlyphEntry, TChar> *)iGlyphTree) -> Connect(iPagePool, &iKey);
+		break;
+	default:
+		User::Leave(KErrNotSupported);
+		break;	
+		}
+	}
+	
+/**
+Searches for the image entry in the binary tree. If fails, it will create a new entry.
+
+@param	aGlyphCode General Unicode character value.
+@param	aGlyphImage Glyph image	bitmap data. The data structure depends on glyph type.
+@param	aGlyphImageSize Size of the glyph image.		
+@param	aEntry Binary tree entry, which comprises OpenVG image(s).
+@param	aDataForeground Pre-allocated buffer, which will be used for setting text VG image.
+
+@see TGlyphEntryCompound
+@see TGlyphEntry
+
+@pre 	Rendering engine has been constructed.
+@post 	Requested  OpenVG images are ready for rendering.
+@return KErrNone if successful;  
+		KErrNotSupported if font type is not supported,  
+		otherwise one of the other system-wide error codes.
+*/
+template <class K>
+void CFontGlyphTree::GlyphImageEntryL(TChar aGlyphCode, const TUint8* aGlyphImage, const TSize& aGlyphImageSize, K& aEntry, TUint8* aDataForeground)
+	{
+	TBtreePos pos;
+	TBool found = EFalse;
+	found = ((TBtreeFix<K, TChar> *)iGlyphTree) -> FindL(pos, aGlyphCode);
+	
+	if(found)
+		{
+		((TBtreeFix<K, TChar> *)iGlyphTree) -> ExtractAtL(pos, aEntry);
+		}
+	else
+		{
+		aEntry.iGlyphCode = aGlyphCode;
+		aEntry.iForeground = VG_INVALID_HANDLE;
+		TInt glyphSizeInByte = 0;
+		
+		switch(iGlyphType)
+			{
+		case EFourColourBlendGlyphBitmap:
+			{
+			((TGlyphEntryCompound&) aEntry).iOutline = VG_INVALID_HANDLE;
+			((TGlyphEntryCompound&) aEntry).iShadow = VG_INVALID_HANDLE;
+			CreateVGImageL(aGlyphImage, aGlyphImageSize, aEntry.iForeground, ((TGlyphEntryCompound&) aEntry).iOutline, ((TGlyphEntryCompound&) aEntry).iShadow, NULL, NULL, NULL);
+			glyphSizeInByte = aGlyphImageSize.iWidth * aGlyphImageSize.iHeight;
+			glyphSizeInByte *= 3; //foreground, shadow, outline
+			break;
+			}
+		case EMonochromeGlyphBitmap:
+			CreateVGImageL(aGlyphImage, aGlyphImageSize, EGray2, aEntry.iForeground, aDataForeground);
+			glyphSizeInByte = (((aGlyphImageSize.iWidth + 31) / 32) << 2) * aGlyphImageSize.iHeight;
+			break;
+		case EAntiAliasedGlyphBitmap:
+			CreateVGImageL(aGlyphImage, aGlyphImageSize, EGray256, aEntry.iForeground, NULL);
+			glyphSizeInByte = aGlyphImageSize.iWidth * aGlyphImageSize.iHeight;
+			break;
+		default:
+			User::Leave(KErrNotSupported);
+			}
+
+		((TBtreeFix<K, TChar> *)iGlyphTree) -> InsertL(pos, aEntry);
+		iCacheSize += glyphSizeInByte;	
+		}
+	}
+
+/**
+Overridden function, which creates Open VG images for foreground, background, shadow and outline components of the font.
+ 
+@param 	aGlyphImage Source bitmap data in 256 grey format. Each pixel value is an index to a constant lookup table. 
+			Four entries of this table represent % of Outline, Shadow, Fill and Background colour to be used to get the final colour to be displayed on screen.
+@param	aGlyphImageSize Size of the glyph bitmap image.
+@param	aForeground Foreground component of the glyph.
+@param	aOutline	Outline component of the glyph.
+@param	aShadow 	Shadow component of the glyph. 
+@param	aPreAllocForeground Pre-allocated buffer which will be used for setting text foreground VG image
+@param	aPreAllocOutline Pre-allocated buffer which will be used for setting text outline VG image
+@param	aPreAllocShadow Pre-allocated buffer which will be used for setting text shadow VG image
+
+@post 	Requested OpenVG images are ready for rendering. 
+*/
+void CFontGlyphTree::CreateVGImageL(const TUint8* aGlyphImage, const TSize& aGlyphImageSize, VGImage& aForeground, VGImage& aOutline, VGImage& aShadow, TUint8* aPreAllocForeground, TUint8* aPreAllocOutline, TUint8* aPreAllocShadow)
+	{
+	TInt dataStride = aGlyphImageSize.iWidth;
+	TInt targetByteCount = dataStride * aGlyphImageSize.iHeight;
+		// Allocate memory and transform source into target format.
+		//
+	TAny* foregroundBuffer = NULL;
+	TAny* outlineBuffer = NULL;
+	TAny* shadowBuffer = NULL;
+	TBool destroyTempBuffer = EFalse;
+	
+	if(aPreAllocForeground && aPreAllocOutline && aPreAllocShadow && 
+			(aGlyphImageSize.iWidth <= KMaxSizeImageOOM.iWidth) && 
+			(aGlyphImageSize.iHeight <= KMaxSizeImageOOM.iHeight))
+		{
+		foregroundBuffer = aPreAllocForeground;
+		outlineBuffer = aPreAllocOutline;
+		shadowBuffer = aPreAllocShadow;
+		}
+	else
+		{
+		foregroundBuffer = User::AllocL(targetByteCount);
+		CleanupStack::PushL(foregroundBuffer);
+		outlineBuffer = User::AllocL(targetByteCount);
+		CleanupStack::PushL(outlineBuffer);
+		shadowBuffer = User::AllocL(targetByteCount);
+		CleanupStack::PushL(shadowBuffer);
+		destroyTempBuffer = ETrue;
+		}	
+
+	TUint8* foregroundByte = static_cast <TUint8*> (foregroundBuffer); 
+	TUint8* outlineByte = static_cast <TUint8*> (outlineBuffer);
+	TUint8* shadowByte = static_cast <TUint8*> (shadowBuffer);
+				
+	const TUint8* endByte = (TUint8*)aGlyphImage + targetByteCount;
+	TUint8* curSrcGlyphImage = const_cast <TUint8*> (aGlyphImage);
+	
+	while (curSrcGlyphImage < endByte)
+		{
+		*outlineByte++ = FourColorBlendLookup[*curSrcGlyphImage] [KOutlineColorIndex];
+		*shadowByte++ = FourColorBlendLookup[*curSrcGlyphImage] [KShadowColorIndex];
+		*foregroundByte++ = FourColorBlendLookup[*curSrcGlyphImage] [KFillColorIndex];
+		curSrcGlyphImage++;
+		}
+
+	const VGImageFormat imageFormat = VG_sL_8;
+	if(aForeground == VG_INVALID_HANDLE)
+		{
+		aForeground = vgCreateImage(imageFormat,
+	                              aGlyphImageSize.iWidth, 
+	                              aGlyphImageSize.iHeight,
+	                              VG_IMAGE_QUALITY_NONANTIALIASED);
+		if(aForeground == VG_INVALID_HANDLE)
+			{
+			User::Leave(KErrNoMemory);
+			}
+		aOutline = vgCreateImage(imageFormat,
+	                              aGlyphImageSize.iWidth, 
+	                              aGlyphImageSize.iHeight,
+	                              VG_IMAGE_QUALITY_NONANTIALIASED);
+		if(aOutline == VG_INVALID_HANDLE)
+			{
+			DestroyVGImage(&aForeground);
+			User::Leave(KErrNoMemory);
+			}
+
+		aShadow = vgCreateImage(imageFormat,
+	                              aGlyphImageSize.iWidth, 
+	                              aGlyphImageSize.iHeight,
+	                              VG_IMAGE_QUALITY_NONANTIALIASED);
+		if(aShadow == VG_INVALID_HANDLE)
+			{
+			DestroyVGImage(&aForeground, &aOutline);
+			User::Leave(KErrNoMemory);	
+			}
+		}
+	
+	vgImageSubData(
+		aForeground, foregroundBuffer, 
+		dataStride,	imageFormat, 
+		0, 0,aGlyphImageSize.iWidth, aGlyphImageSize.iHeight);
+	
+#ifdef DRAWGLYPH_MULTIPLY_MODE
+		VGImage image = vgCreateImage(VG_sARGB_8888_PRE, aGlyphImageSize.iWidth, aGlyphImageSize.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED);		
+		vgColorMatrix(image, aForeground, KColorMatrix);
+		vgDestroyImage(aForeground);
+		aForeground = image;
+#endif // DRAWGLYPH_MULTIPLY_MODE
+		
+	vgImageSubData(
+		aOutline, outlineBuffer, 
+		dataStride,	imageFormat, 
+		0, 0, aGlyphImageSize.iWidth, aGlyphImageSize.iHeight);
+	
+#ifdef DRAWGLYPH_MULTIPLY_MODE
+		image = vgCreateImage(VG_sARGB_8888_PRE, aGlyphImageSize.iWidth, aGlyphImageSize.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED);		
+		vgColorMatrix(image, aOutline, KColorMatrix);
+		vgDestroyImage(aOutline);
+		aOutline = image;
+#endif // DRAWGLYPH_MULTIPLY_MODE
+		
+	vgImageSubData(
+		aShadow, shadowBuffer, 
+		dataStride,	imageFormat, 
+		0, 0, aGlyphImageSize.iWidth, aGlyphImageSize.iHeight);
+	
+#ifdef DRAWGLYPH_MULTIPLY_MODE
+		image = vgCreateImage(VG_sARGB_8888_PRE, aGlyphImageSize.iWidth, aGlyphImageSize.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED);		
+		vgColorMatrix(image, aShadow, KColorMatrix);
+		vgDestroyImage(aShadow);
+		aShadow = image;
+#endif // DRAWGLYPH_MULTIPLY_MODE	
+	
+	if(destroyTempBuffer)
+		{
+		CleanupStack::PopAndDestroy(3, foregroundBuffer);
+		}
+	}
+
+/**
+Overridden function, which creates OpenVG images for monochrome and anti-aliased fonts.
+ 
+@param 	aGlyphImage Data source bitmap in 256 or 2 Grey format. 
+@param 	aGlyphImageSize Glyph image data size.
+@param 	aDisplayMode Image display mode.
+@param	aForeground Foreground component of the glyph.
+@param	aPreAllocForeground Pre-allocated buffer which will be used for setting foreground VG image
+
+@post 	Requested OpenVG image is ready for rendering. 
+
+@panic 	Panic if bitmap display mode is not 256 grey or 2 grey.
+*/
+void CFontGlyphTree::CreateVGImageL(const TUint8* aGlyphImage, const TSize& aGlyphImageSize, TDisplayMode aDisplayMode, VGImage& aForeground, TUint8* aPreAllocForeground)
+	{
+	GRAPHICS_ASSERT_DEBUG((aDisplayMode == EGray256) || (aDisplayMode == EGray2), EDirectGdiPanicInvalidDisplayMode);
+	GRAPHICS_ASSERT_DEBUG(aGlyphImage, EDirectGdiPanicInvalidParameter);
+	
+	VGImageFormat imageFormat = VG_IMAGE_FORMAT_INVALID;
+	TInt  vgCompatibleSourceStride = 0x00;
+	TUint32 binaryDataArray[32];
+	TUint8* binaryData = NULL;
+	TUint8* tempBuffer = NULL;	
+	
+	if(aDisplayMode == EGray256)
+		{
+		imageFormat = VG_sL_8;
+		vgCompatibleSourceStride = aGlyphImageSize.iWidth; 
+		binaryData = const_cast <TUint8*> (aGlyphImage);
+		}
+	else //EGray2
+		{
+		imageFormat = VG_BW_1;
+		vgCompatibleSourceStride = ((aGlyphImageSize.iWidth + 31) / 32) << 2;
+		if (aGlyphImageSize.iWidth > 30 || aGlyphImageSize.iHeight > 32)
+			{
+			binaryData = aPreAllocForeground;
+			if(!binaryData)
+				{
+				tempBuffer = (TUint8*) User::AllocL(vgCompatibleSourceStride * aGlyphImageSize.iHeight);
+				CleanupStack::PushL(tempBuffer);
+				binaryData = tempBuffer;
+				}
+			DecodeBinaryDataExLarge(aGlyphImageSize, aGlyphImage, vgCompatibleSourceStride, reinterpret_cast <TUint32*> (binaryData));
+			}
+		else
+			{
+			DecodeBinaryData(aGlyphImageSize, aGlyphImage, binaryDataArray);
+			binaryData = reinterpret_cast <TUint8*> (binaryDataArray);		
+			}
+		}
+
+	if(aForeground == VG_INVALID_HANDLE)
+		{
+		aForeground = vgCreateImage(imageFormat,
+                              aGlyphImageSize.iWidth, 
+                              aGlyphImageSize.iHeight,
+                              VG_IMAGE_QUALITY_NONANTIALIASED);
+		}
+	
+	if (aForeground != VG_INVALID_HANDLE)
+		{
+			// Copy from the source image to our new VGImage
+		vgImageSubData(aForeground, binaryData, vgCompatibleSourceStride,	imageFormat, 
+			0,	0, aGlyphImageSize.iWidth, aGlyphImageSize.iHeight);
+		
+#ifdef DRAWGLYPH_MULTIPLY_MODE
+		VGImage image = vgCreateImage(VG_sARGB_8888_PRE, aGlyphImageSize.iWidth, aGlyphImageSize.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED);		
+		vgColorMatrix(image, aForeground, KColorMatrix);
+		vgDestroyImage(aForeground);
+		aForeground = image;
+#endif
+		}
+	else
+		{
+		if(tempBuffer)
+			{
+			CleanupStack::PopAndDestroy(tempBuffer);	
+			}
+		User::Leave(KErrNoMemory);
+		}
+		
+	if(tempBuffer)
+		{
+		CleanupStack::PopAndDestroy(tempBuffer);	
+		}
+	}
+
+/**
+Decodes binary data for monochrome bitmap.
+
+@param aDataSize Image size.
+@param aData Pointer to a source buffer.
+@param aBinaryData Pointer to a destination buffer.
+*/
+void CFontGlyphTree::DecodeBinaryData(const TSize& aDataSize,
+								const TUint8* aData,
+								TUint32* aBinaryData) 
+	{
+	//Divert if the character is larger than expected; the criterion
+	//for choosing this function is only a heuristic, because it's perfectly legal for
+	//a character's bitmap to be wider than its escapement.
+	//
+	//Use a dummy value (0) for semi-ascent because this character is not italic and so semi-ascent
+	//is irrelevant; it's used for pseudo-italic slanting.
+	
+	TInt dataheight = aDataSize.iHeight;
+	TInt datalength = aDataSize.iWidth;
+	
+	TInt bitindex=0;
+	TInt16 repeatcount=0;
+	TUint32* binarydataptr=aBinaryData;
+	TUint32* binarydataptrlimit;
+	for(TInt charline=0;charline<dataheight;charline+=repeatcount) // for lines in the character...
+		{
+		repeatcount=Load16(aData+(bitindex>>3));
+		repeatcount>>=bitindex&7;
+		TInt multilineflag=repeatcount&1;
+		repeatcount>>=1;
+		repeatcount&=0xf;
+		bitindex+=5;
+		binarydataptrlimit=aBinaryData+charline+repeatcount;
+		if(multilineflag)
+			{
+			while(binarydataptr<binarydataptrlimit)
+				{
+				TInt chardataoffsetptr=TInt(aData)+(bitindex>>3);
+				TUint32* chardataword=(TUint32*)(chardataoffsetptr&~3);
+				TInt bitshift=bitindex&7;
+				bitshift+=(chardataoffsetptr&3)<<3;
+				*binarydataptr=(*chardataword++)>>bitshift;
+				if(bitshift) *binarydataptr|=(*chardataword<<(32-bitshift));
+				bitindex+=datalength;
+				binarydataptr++;
+				}
+			}
+		else
+			{
+			TInt chardataoffsetptr=TInt(aData)+(bitindex>>3);
+			TUint32* chardataword=(TUint32*)(chardataoffsetptr&~3);
+			TInt bitshift=bitindex&7;
+			bitshift+=(chardataoffsetptr&3)<<3;
+			TUint32 data=(*chardataword++)>>bitshift;
+			if(bitshift) data|=(*chardataword<<(32-bitshift));
+			while(binarydataptr<binarydataptrlimit)
+				*binarydataptr++=data;
+			bitindex+=datalength;
+			}
+		}
+	}
+	
+/**
+Decodes binary data for extra large monochrome bitmap.
+
+@param aDataSize Image size.
+@param aData Pointer to a source buffer.
+@param aStride Image data stride.
+@param aBinaryData Pointer to a destination buffer.
+*/
+void CFontGlyphTree::DecodeBinaryDataExLarge(const TSize& aDataSize, const TUint8* aData, TInt aStride,
+											TUint32* aBinaryData)
+	{
+	const TInt datalength = aDataSize.iWidth;
+	const TInt dataheight = aDataSize.iHeight;
+	TInt bitindex=0;
+	TInt16 repeatcount=0;
+	TUint32* slbuffer=aBinaryData;
+	const TInt slwords=aStride;
+
+	for(TInt charline=0;charline<dataheight;charline+=repeatcount) // for lines in the character...
+		{
+		repeatcount=Load16(aData+(bitindex>>3));
+		repeatcount>>=bitindex&7;
+		const TInt multilineflag=repeatcount&1;
+		repeatcount>>=1;
+		repeatcount&=0xf;
+		bitindex+=5;
+		if(multilineflag)
+			{
+			for(TInt currentline=0;currentline<repeatcount;currentline++)
+				{
+				CopyCharLine(slbuffer,slwords,aData+(bitindex>>3),bitindex&7,datalength, 1);
+				bitindex+=datalength;
+				}
+			}
+		else
+			{
+			CopyCharLine(slbuffer,slwords,aData+(bitindex>>3),bitindex&7,datalength, repeatcount);
+			bitindex+=datalength;
+			}
+		}
+	}
+
+/**
+Copies image data line(s) to a destination.
+
+@param aBinaryDataPtr pointer to a destination buffer.
+@param aBufferWords Stride of the image.
+@param aData Pointer to a source buffer.
+@param aBitShift Number of bits, binary data will be shifted. 
+@param aCharWidth Width of the image.
+@param aRepeatCount Number of lines to copy.
+
+@panic DGDIAdapter 1018, if a null binary data pointer is passed in.
+*/
+void CFontGlyphTree::CopyCharLine(TUint32*& aBinaryDataPtr,TInt aBufferWords,const TUint8* aData,TInt aBitShift,TInt aCharWidth, TInt16 aRepeatCount)
+	{
+	GRAPHICS_ASSERT_DEBUG(aBinaryDataPtr, EDirectGdiPanicInvalidPointer);//this shouldn't happen, as we always allocate memory prior to call this function 
+	aBitShift&=7;
+	TInt wordstocopy=(aCharWidth+31)>>5;
+	if(wordstocopy>aBufferWords) wordstocopy=aBufferWords;
+	TUint32* ptrlimit=aBinaryDataPtr+wordstocopy;
+	TUint32* dataword=(TUint32*)(TInt(aData)&~3);
+	aBitShift+=(TInt(aData)-TInt(dataword))<<3;
+	
+	TUint32* startBinaryDataPtr = aBinaryDataPtr;
+	while(aBinaryDataPtr<ptrlimit)
+		{
+		*aBinaryDataPtr=*dataword++;
+		*aBinaryDataPtr>>=aBitShift;
+		if(aBitShift) *aBinaryDataPtr|=(*dataword<<(32-aBitShift));
+		aBinaryDataPtr++;
+		}
+	
+	TUint32* curStartBinaryDataPtr = aBinaryDataPtr;
+	TInt byteToCopy = wordstocopy << 2;
+	while(aRepeatCount > 1)
+		{
+		Mem::Copy(curStartBinaryDataPtr, startBinaryDataPtr, byteToCopy);
+		curStartBinaryDataPtr += wordstocopy;
+		
+		aRepeatCount--;
+		}
+	aBinaryDataPtr = curStartBinaryDataPtr;
+	}
+
+/**
+Destroys OpenVG images and set variables to NULL
+
+@param aForeground Pointer to the foreground VGImage.
+@param aOutline Pointer to the outline VGImage.
+@param aShadow Pointer to the shadow VGImage.
+*/
+void CFontGlyphTree::DestroyVGImage(VGImage* aForeground, VGImage* aOutline, VGImage* aShadow)
+	{
+	if(aForeground && *aForeground)
+		{
+		vgDestroyImage(*aForeground);
+		*aForeground = VG_INVALID_HANDLE;
+		}
+	if(aOutline && *aOutline)
+		{
+		vgDestroyImage(*aOutline);
+		*aOutline = VG_INVALID_HANDLE;
+		}
+	if(aShadow && *aShadow)
+		{
+		vgDestroyImage(*aShadow);
+		*aShadow = VG_INVALID_HANDLE;
+		}
+	}
+
+/**
+Goes through all entries and deletes VG images.
+*/
+void CFontGlyphTree::DestroyAllVGImagesL()
+	{
+	if(iGlyphTree)
+		{
+		TBool isEntry = EFalse;
+		TBtreePos pos;
+		isEntry = iGlyphTree -> FirstL(pos);
+		//go through all entries and delete VG images
+		while (isEntry)
+			{
+			TGlyphEntry entry;
+			TGlyphEntryCompound entryC;
+			(iGlyphType == EFourColourBlendGlyphBitmap) ?
+					((TBtreeFix<TGlyphEntryCompound, TChar> *) iGlyphTree) -> ExtractAtL(pos, entryC) :
+					((TBtreeFix<TGlyphEntry, TChar> *) iGlyphTree) -> ExtractAtL(pos, entry);
+			
+			if(iGlyphType == EFourColourBlendGlyphBitmap)
+				{
+				DestroyVGImage(&entryC.iForeground, &entryC.iOutline, &entryC.iShadow);
+				}
+			else
+				{
+				DestroyVGImage(&entry.iForeground);
+				}	
+			isEntry = iGlyphTree -> NextL(pos);
+			}
+		iCacheSize = 0;
+		iGlyphTree -> ClearL();
+		}
+	}
+	
+/**
+Allows OpenVG images to be created in OOM conditions. Images will not be added to the binary tree. 
+*/
+template <class K>
+void CFontGlyphTree::GlyphImageEntryOOML(TGlyphBitmapType aGlyphType, const TUint8* aGlyphImage, const TSize& aGlyphImageSize, K& aEntry, TUint8* aData, TUint8* aDataOutline, TUint8* aDataShadow)
+	{
+	switch(aGlyphType)
+		{
+	case EFourColourBlendGlyphBitmap:
+		{
+		CreateVGImageL(aGlyphImage, aGlyphImageSize, aEntry.iForeground, ((TGlyphEntryCompound&) aEntry).iOutline, ((TGlyphEntryCompound&) aEntry).iShadow, aData, aDataOutline, aDataShadow);
+		break;
+		}
+	case EMonochromeGlyphBitmap:
+		CreateVGImageL(aGlyphImage, aGlyphImageSize, EGray2, aEntry.iForeground, aData);
+		break;
+	case EAntiAliasedGlyphBitmap:
+		CreateVGImageL(aGlyphImage, aGlyphImageSize, EGray256, aEntry.iForeground, aData);
+		break;
+	default:
+		User::Leave(KErrNotSupported);
+		}
+	}
+	
+//--------------class CFontGlyphImageStorage --------------------
+/**
+Constructor for the font glyph image storage.
+
+@param aMaxCacheSize The maximum cache size in bytes. If storage exceeds this value, the least usable binary tree will be destroyed.
+*/
+CFontGlyphImageStorage::CFontGlyphImageStorage(TInt aMaxCacheSize) :
+						iFontTreeList(128),
+						iMaxCacheSize(aMaxCacheSize)
+	{
+	}
+
+/**
+Destructor for the font glyph image storage.
+
+Removes and destroys all binary tree's entries in the list.
+*/
+CFontGlyphImageStorage::~CFontGlyphImageStorage()
+	{
+	CleanGlyphImageCache();
+	DeletePreAllocatedImages();
+	}
+
+/**
+The function will free memory by deleting the least usable font tree, if the size of the cache exceeds 
+some pre-defined value. 
+
+@see MFontGlyphImageStorage
+@panic DGDIAdapter 46, if there is an inconsistency in the internal glyph cache structure.
+*/
+void CFontGlyphImageStorage::CleanCacheIfRequired()
+	{
+	if(iCacheSize > iMaxCacheSize)
+		{
+		if(iFontTreeList.Count() == 1)//if it is only one tree, just delete all images
+			{
+			TInt aOldTreeSize = iFontTreeList[0]->CacheSize();
+			TRAP_IGNORE(iFontTreeList[0]->DestroyAllVGImagesL());
+			GRAPHICS_ASSERT_DEBUG(0 == (iCacheSize - (aOldTreeSize - iFontTreeList[0]->CacheSize())), EDirectGdiPanicGlyphCacheDataInconsistent);
+			iCacheSize = 0;
+			}
+		else
+			{
+			CFontGlyphTree* fontTree = iFontTreeList[iFontTreeList.Count() - 1];
+			iFontTreeList.Remove(iFontTreeList.Count() - 1);
+			GRAPHICS_ASSERT_DEBUG(iCacheSize >= fontTree->CacheSize(), EDirectGdiPanicGlyphCacheDataInconsistent);
+			iCacheSize -= fontTree->CacheSize(); //since we removed the tree, we must update overall cache size to reflect this fact
+			delete fontTree;
+			}	
+		}
+	}
+
+/**
+Removes all glyph trees from the storage. 
+
+@see MFontGlyphImageStorage
+*/
+void CFontGlyphImageStorage::CleanGlyphImageCache()
+	{
+	iFontTreeList.ResetAndDestroy();
+	iCacheSize = 0;
+	}
+
+/**
+@test
+
+@return Current glyph cache size in bytes.
+@see MFontGlyphImageStorage
+*/
+TInt CFontGlyphImageStorage::GlyphCacheSize() const
+	{
+	return iCacheSize;
+	}
+
+/**
+Sets the maximum size in bytes of the glyph cache. Checks the current size of
+the cache and sets the maximum cache size if the current cache size is smaller
+or equal to aCacheSize.
+@param aMaxCacheSize The maximum size in bytes to allow for the glyph cache.
+@return KErrNone if the maximum cache size has been changed successfully,
+KErrArgument if aMaxCacheSize is smaller than the current cache size. 
+ */
+TInt CFontGlyphImageStorage::SetMaxGlyphCacheSize(TInt aMaxCacheSize)
+	{
+	if (iCacheSize <= aMaxCacheSize)
+		{
+		iMaxCacheSize = aMaxCacheSize;
+		return KErrNone;
+		}
+	
+	return KErrArgument;
+	}
+	
+/**
+@return Max glyph cache size in bytes.
+@see MFontGlyphImageStorage
+*/
+TInt CFontGlyphImageStorage::MaxGlyphCacheSize() const
+	{
+	return iMaxCacheSize;
+	}
+
+/**
+Fills aFontListId parameter with font Id in order from most to least usable. 
+
+@test
+@see MFontGlyphImageStorage
+
+@return KErrNone, if the insertion is successful, otherwise one of the system wide error codes.
+*/
+TInt CFontGlyphImageStorage::FontIdInOrder(RArray<TUint32> & aFontListId) const
+	{
+	TInt err = KErrNone;
+	aFontListId.Reset();
+	
+	for(TInt index = 0; (index < iFontTreeList.Count()) && (err == KErrNone); index++)
+		{
+		CFontGlyphTree* glyphTree = iFontTreeList[index];
+		err = aFontListId.Append(glyphTree->FontId());
+		}
+		
+	return err;
+	}
+
+/**
+Enforce the system to emulate OOM failure. As sequence pre-allocated images will be used.
+
+@test
+@see MFontGlyphImageStorage
+*/
+#ifdef _DEBUG
+void CFontGlyphImageStorage::EnforceOOMFailure(TBool aEnforce)
+	{
+	iEnforceOOM = aEnforce;
+	}
+#else
+void CFontGlyphImageStorage::EnforceOOMFailure(TBool /*aEnforce*/)
+	{
+	}
+#endif
+
+/**
+Retrieves OpenVG images from the font image cache. If the image doesn't exist, the function will create a new one from the bitmap glyph image and 
+add it into the font image cache.
+Each font corresponds to a particular tree of glyph images.
+The function's search is performed in two steps:
+	1.	It tries to identify the glyph tree associated with the font. Otherwise a new tree will be created
+	2.	Within the tree the function will search for the particular glyph entry. Otherwise a new glyph entry will be created
+If the size of the cache exceeds some pre-defined value, the least usable tree with all its entries will be deleted.
+If the function fails to place the element into the tree due to shortage of memory, it will 
+still try to create VGImages without adding them to the binary tree.
+@see	CVgEngine::DrawGlyph
+@see 	MFontGlyphImageStorage
+
+@param	aFontId Unique Font Id.
+@param	aGlypCode General Unicode character value.
+@param	aGlyphBitmapType A type for the format of a glyph bitmap.
+@param	aGlyphImage Glyph bitmap image data.
+@param	aGlyphImageSize The size of the glyph bitmap image data.
+@param  aImageForeground Pointer to VGImage text foreground handle.
+@param  aImageShadow Pointer to VGImage text shadow handle.
+@param  aImageOutline Pointer to VGImage text outline handle.
+
+@pre 	Rendering engine has been constructed.
+@post 	Requested  OpenVG images are ready for rendering. 
+
+@panic DGDIAdapter 1018, if a null glyph image pointer is passed in.
+@return On success KErrNone, 
+		KErrArgument if passed parameters are not correct,
+		KErrNotSupported if functionality is not supported,	otherwise one of the other system-wide error codes.
+*/
+TInt CFontGlyphImageStorage::GlyphImage(TUint32 aFontId, TChar aGlypCode, TGlyphBitmapType aGlyphBitmapType, const TUint8* aGlyphImage, const TSize& aGlyphImageSize, 
+				TAny* aImageForeground, TAny* aImageShadow, TAny* aImageOutline)
+	{
+	if((aGlyphImageSize.iHeight <= 0) || (aGlyphImageSize.iWidth <= 0))
+		{
+		return KErrArgument;
+		}
+	GRAPHICS_ASSERT_ALWAYS(aGlyphImage, EDirectGdiPanicInvalidPointer); // maybe needs to change assertion type
+	GRAPHICS_ASSERT_ALWAYS(aImageForeground, EDirectGdiPanicInvalidPointer); // maybe needs to change assertion type
+	GRAPHICS_ASSERT_ALWAYS((aImageShadow && aImageOutline) || (aGlyphBitmapType != EFourColourBlendGlyphBitmap), EDirectGdiPanicInvalidPointer); // maybe needs to change assertion type
+
+	TInt res = KErrNone;
+	CFontGlyphTree* fontTree = NULL;
+	TInt index = 0;
+
+	for(; index < iFontTreeList.Count(); index++)
+		{
+		CFontGlyphTree* fontTreeTemp = iFontTreeList[index];
+		if(fontTreeTemp->FontId() == aFontId)
+			{
+			fontTree = fontTreeTemp;
+			break;
+			}
+		}
+
+	if(!fontTree)
+		{ 
+#ifdef _DEBUG
+		if(!iEnforceOOM)
+			{
+#endif		
+			//there is no tree for that font, thus create one
+			TRAP(res, fontTree = CFontGlyphTree::NewL(aFontId, aGlyphBitmapType));
+			if(res == KErrNone)
+				{
+				res = iFontTreeList.Insert(fontTree, 0);
+				if(res != KErrNone)
+					{
+					delete fontTree;
+					fontTree = NULL;
+					}
+				}
+#ifdef _DEBUG
+			}
+#endif		
+		}
+	else if(index != 0)
+		{//reorder the tree
+		iFontTreeList.Remove(index);
+		res = iFontTreeList.Insert(fontTree, 0);
+		if(res != KErrNone)
+			{ //we have to delete fontTree as it is not stored anywhere.
+			delete fontTree;
+			fontTree = NULL;
+			}
+		}	
+
+#ifdef _DEBUG	
+	if(iEnforceOOM && (res == KErrNone))
+		{
+		res = KErrNoMemory;	
+		}
+#endif		
+	if(res == KErrNone)
+		{
+		CleanCacheIfRequired();
+		TInt treeCacheSize = fontTree->CacheSize();
+		if(aGlyphBitmapType == EFourColourBlendGlyphBitmap)
+			{
+			TRAP(res, fontTree->GlyphImageEntryL(aGlypCode, aGlyphImage, aGlyphImageSize, iEntryCompound, NULL));
+			}
+		else
+			{
+			TRAP(res, fontTree->GlyphImageEntryL(aGlypCode, aGlyphImage, aGlyphImageSize, iEntry, aGlyphBitmapType == EMonochromeGlyphBitmap ? iForegroundData : NULL));
+			}	
+		if(res == KErrNone)
+			{
+			iCacheSize += (fontTree->CacheSize() - treeCacheSize);
+			if(aGlyphBitmapType == EFourColourBlendGlyphBitmap)
+				{
+				*(static_cast <VGImage*> (aImageForeground)) = iEntryCompound.iForeground;
+				*(static_cast <VGImage*> (aImageShadow)) = iEntryCompound.iShadow;
+				*(static_cast <VGImage*> (aImageOutline)) = iEntryCompound.iOutline;
+				}
+			else
+				{
+				if(aImageShadow)
+					{
+					*(static_cast <VGImage*> (aImageShadow)) = VG_INVALID_HANDLE;
+					}
+				if(aImageOutline)
+					{
+					*(static_cast <VGImage*> (aImageOutline)) = VG_INVALID_HANDLE;
+					}
+
+				*(static_cast <VGImage*> (aImageForeground)) = iEntry.iForeground;
+				}	
+			}
+		}
+		
+	//create glyph images for OOM conditions, without putting the entry into the tree
+	if((res == KErrNoMemory) && iImagesPreAllocated && (iImageSize.iWidth >= aGlyphImageSize.iWidth ) && (iImageSize.iHeight >= aGlyphImageSize.iHeight))
+		{
+		const TInt bufferSize = iImageSize.iWidth * iImageSize.iHeight;
+		Mem::FillZ(iForegroundData, bufferSize);
+		VGImageFormat imageFormat = VG_sL_8;
+		TInt vgCompatibleSourceStride = iImageSize.iWidth;
+
+		if(aGlyphBitmapType == EFourColourBlendGlyphBitmap)
+			{
+			Mem::FillZ(iShadowData, bufferSize);
+			Mem::FillZ(iOutlineData, bufferSize);
+			iEntryCompound.iForeground = iImageForeground;
+			iEntryCompound.iOutline = iImageOutline;
+			iEntryCompound.iShadow = iImageShadow;
+			
+			vgImageSubData(iEntryCompound.iForeground, iForegroundData, vgCompatibleSourceStride,	imageFormat, 
+					0,	0, iImageSize.iWidth, iImageSize.iHeight);
+
+			vgImageSubData(iEntryCompound.iOutline, iOutlineData, vgCompatibleSourceStride,	imageFormat, 
+					0,	0, iImageSize.iWidth, iImageSize.iHeight);
+
+			vgImageSubData(iEntryCompound.iShadow, iShadowData, vgCompatibleSourceStride,	imageFormat, 
+					0,	0, iImageSize.iWidth, iImageSize.iHeight);
+
+			TRAP_IGNORE(CFontGlyphTree::GlyphImageEntryOOML(aGlyphBitmapType, aGlyphImage, aGlyphImageSize, iEntryCompound, iForegroundData, iShadowData, iOutlineData));
+			*(static_cast <VGImage*> (aImageForeground)) = iImageForeground;
+			*(static_cast <VGImage*> (aImageShadow)) = iImageShadow;
+			*(static_cast <VGImage*> (aImageOutline)) = iImageOutline;
+			}
+		else
+			{
+			iEntry.iForeground = iImageForeground;
+			vgImageSubData(iEntry.iForeground, iForegroundData, vgCompatibleSourceStride,	imageFormat, 
+				0,	0, iImageSize.iWidth, iImageSize.iHeight);
+			
+			TRAP_IGNORE(CFontGlyphTree::GlyphImageEntryOOML(aGlyphBitmapType, aGlyphImage, aGlyphImageSize, iEntry, iForegroundData, NULL, NULL));
+			*(static_cast <VGImage*> (aImageForeground)) = iImageForeground;
+			}	
+		}
+	
+	return res;
+	}
+
+/**
+Creates VGImages for use in low memory conditions
+*/
+TInt CFontGlyphImageStorage::PreAllocateImages()
+	{
+	iImageSize = KMaxSizeImageOOM;
+
+#ifdef DRAWGLYPH_MULTIPLY_MODE
+	// For image_multiply mode need 32bits for each glyph instrad of 8 for non-multiply mode.
+	const TInt bufferSize = iImageSize.iWidth * iImageSize.iHeight * 4;
+#else
+	const TInt bufferSize = iImageSize.iWidth * iImageSize.iHeight;
+#endif
+	if(!iForegroundData)
+		{
+		iForegroundData = (TUint8*) User::Alloc(bufferSize);
+		if(!iForegroundData)
+			{
+			return KErrNoMemory;
+			}
+		}
+	
+	if(!iShadowData)
+		{
+		iShadowData = (TUint8*) User::Alloc(bufferSize);
+		if(!iShadowData)
+			{
+			return KErrNoMemory;
+			}
+		}
+
+	if(!iOutlineData)
+		{
+		iOutlineData = (TUint8*) User::Alloc(bufferSize);
+		if(!iOutlineData)
+			{
+			return KErrNoMemory;
+			}
+		}
+
+	const VGImageFormat imageFormat = VG_sL_8;
+	if(iImageForeground == VG_INVALID_HANDLE)
+		{
+		
+		iImageForeground = vgCreateImage(imageFormat,
+	                              iImageSize.iWidth, 
+	                              iImageSize.iHeight,
+	                              VG_IMAGE_QUALITY_NONANTIALIASED);
+		if(iImageForeground == VG_INVALID_HANDLE)
+			{
+			return KErrNoMemory;
+			}
+		}
+
+	if(iImageShadow == VG_INVALID_HANDLE)
+		{
+		iImageShadow = vgCreateImage(imageFormat,
+	                              iImageSize.iWidth, 
+	                              iImageSize.iHeight,
+	                              VG_IMAGE_QUALITY_NONANTIALIASED);
+		if(iImageShadow == VG_INVALID_HANDLE)
+			{
+			return KErrNoMemory;
+			}
+		}
+
+	if(iImageOutline == VG_INVALID_HANDLE)
+		{
+		iImageOutline = vgCreateImage(imageFormat,
+	                              iImageSize.iWidth, 
+	                              iImageSize.iHeight,
+	                              VG_IMAGE_QUALITY_NONANTIALIASED);
+		if(iImageOutline == VG_INVALID_HANDLE)
+			{
+			return KErrNoMemory;
+			}
+		}
+
+	iImagesPreAllocated = ETrue;	
+	return KErrNone;
+	}
+
+/**
+Deletes all pre-allocated images and frees buffers. 
+*/
+void CFontGlyphImageStorage::DeletePreAllocatedImages()
+	{
+	if(iForegroundData)
+		{
+		User::Free(iForegroundData);
+		iForegroundData = NULL;
+		}
+
+	if(iShadowData)
+		{
+		User::Free(iShadowData);
+		iShadowData = NULL;
+		}
+
+	if(iOutlineData)
+		{
+		User::Free(iOutlineData);
+		iOutlineData = NULL;
+		}
+		
+	if(iImageForeground != VG_INVALID_HANDLE)
+		{
+		vgDestroyImage(iImageForeground);
+		iImageForeground = VG_INVALID_HANDLE;
+		}
+		
+	if(iImageShadow != VG_INVALID_HANDLE)
+		{
+		vgDestroyImage(iImageShadow);
+		iImageShadow = VG_INVALID_HANDLE;
+		}
+		
+	if(iImageOutline != VG_INVALID_HANDLE)
+		{
+		vgDestroyImage(iImageOutline);
+		iImageOutline = VG_INVALID_HANDLE;
+		}
+	iImagesPreAllocated = EFalse;	
+	}