diff -r 000000000000 -r 5d03bc08d59c graphicsdeviceinterface/directgdiadaptation/hwsrc/glyphimagecache.cpp --- /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 + +//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 (EBtreeFast); + ((TBtreeFix *)iGlyphTree) -> Connect(iPagePool, &iKey); + break; + case EMonochromeGlyphBitmap: + case EAntiAliasedGlyphBitmap: + iGlyphTree = new (ELeave) TBtreeFix (EBtreeFast); + ((TBtreeFix *)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 +void CFontGlyphTree::GlyphImageEntryL(TChar aGlyphCode, const TUint8* aGlyphImage, const TSize& aGlyphImageSize, K& aEntry, TUint8* aDataForeground) + { + TBtreePos pos; + TBool found = EFalse; + found = ((TBtreeFix *)iGlyphTree) -> FindL(pos, aGlyphCode); + + if(found) + { + ((TBtreeFix *)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 *)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 (foregroundBuffer); + TUint8* outlineByte = static_cast (outlineBuffer); + TUint8* shadowByte = static_cast (shadowBuffer); + + const TUint8* endByte = (TUint8*)aGlyphImage + targetByteCount; + TUint8* curSrcGlyphImage = const_cast (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 (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 (binaryData)); + } + else + { + DecodeBinaryData(aGlyphImageSize, aGlyphImage, binaryDataArray); + binaryData = reinterpret_cast (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>3)); + repeatcount>>=bitindex&7; + TInt multilineflag=repeatcount&1; + repeatcount>>=1; + repeatcount&=0xf; + bitindex+=5; + binarydataptrlimit=aBinaryData+charline+repeatcount; + if(multilineflag) + { + while(binarydataptr>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>3)); + repeatcount>>=bitindex&7; + const TInt multilineflag=repeatcount&1; + repeatcount>>=1; + repeatcount&=0xf; + bitindex+=5; + if(multilineflag) + { + for(TInt currentline=0;currentline>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>=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 *) iGlyphTree) -> ExtractAtL(pos, entryC) : + ((TBtreeFix *) 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 +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 & 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 (aImageForeground)) = iEntryCompound.iForeground; + *(static_cast (aImageShadow)) = iEntryCompound.iShadow; + *(static_cast (aImageOutline)) = iEntryCompound.iOutline; + } + else + { + if(aImageShadow) + { + *(static_cast (aImageShadow)) = VG_INVALID_HANDLE; + } + if(aImageOutline) + { + *(static_cast (aImageOutline)) = VG_INVALID_HANDLE; + } + + *(static_cast (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 (aImageForeground)) = iImageForeground; + *(static_cast (aImageShadow)) = iImageShadow; + *(static_cast (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 (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; + }