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