--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/uiacceltk/hitchcock/coretoolkit/src/HuiCanvasTextureCache.cpp Tue Feb 02 07:56:43 2010 +0200
@@ -0,0 +1,3475 @@
+/*
+* Copyright (c) 2006-2008 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 "huicanvastexturecache.h"
+#include "uiacceltk/HuiImage.h"
+#include "uiacceltk/HuiTexture.h"
+#include "uiacceltk/HuiEnv.h"
+#include "uiacceltk/HuiUtil.h"
+#include "uiacceltk/HuiStatic.h"
+#include "huicanvasgc.h"
+#include "HuiRenderPlugin.h"
+#include "huicanvasrenderbuffer.h"
+
+#include <e32cmn.h>
+#include <bitdev.h>
+#include <AknLayoutFont.h>
+#include <e32property.h>
+
+// Enable this for debugging cache usage
+//#define HUI_DEBUG_PRINT_CANVAS_TEXTURE_CACHE
+//#define HUI_DEBUG_PRINT_CANVAS_TEXTURE_CACHE_EGL
+//#define HUI_DEBUG_PRINT_CANVAS_TEXTURE_CACHE_EXTENDED
+
+// Enable this for debugging performance
+//#define HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
+
+/** Magic S60 font constant */
+const TInt KHuiFontVerticalShiftInPixels = 1;
+
+/** Initial touch count value */
+const TInt KHuiInitialBitmapTouchCount = -1;
+
+/** Estimated bits per pixel for all textures */
+const TReal32 KHuiTextureEstimatedBpp = 32;
+
+/** Estimated bits per pixel for rasterized canvas texts */
+const TReal32 KHuiCanvasTextEstimatedBpp = 8;
+
+/** Estimated bits per pixel for canvas images */
+const TReal32 KHuiCanvasImageEstimatedBpp = 32;
+
+/** Estimated bits per pixel for canvas render buffers */
+const TReal32 KHuiCanvasRenderBufferEstimatedBpp = 32;
+
+/** Constant to define target how much memory UI textures should use,
+ this is not a hard limit but effects how long unused textures are cached */
+const TInt KHuiMaxRecommendedTextureAmountInKBytes = 4096;
+
+/** Constant to define target how much memory UI render buffers should use,
+ this is not a hard limit but effects how long unused render buffers are cached */
+const TInt KHuiMaxRecommendedRenderBufferAmountInKBytes = 0;
+
+/** Ratio how cache is divided between canvas texts and images */
+const TReal32 KHuiCanvasUnusedTextImageCacheRatio = 0.1f;
+
+/** Max amount of recycled texture objects */
+const TInt KHuiMaxRecycledTextureCount = 100;
+
+/** Use color modulation or not for setting text color */
+const TBool KHuiCanvasTextUseColorModulation = ETrue;
+
+/** Store bitmap pointers to avoid handle duplication */
+const TBool KHuiCanvasKeepBitmapPointer = ETrue;
+
+CHuiCanvasImage::CHuiCanvasImage() :
+ iTexture(NULL),
+ iCache(NULL)
+ {
+ }
+
+CHuiCanvasImage::~CHuiCanvasImage()
+ {
+ if (iCache && iTexture)
+ {
+ iCache->DeleteRecycledTexture(iTexture);
+ }
+ else
+ {
+ delete iTexture;
+ }
+
+ iActiveUsers.Close();
+ }
+
+void CHuiCanvasImage::RefreshUser(const CHuiCanvasVisual& aUser)
+ {
+ if (iActiveUsers.FindInAddressOrder(&aUser) == KErrNotFound)
+ {
+ iActiveUsers.InsertInAddressOrder(&aUser);
+ }
+
+ // Update last usage time
+ iLastUsed.UniversalTime();
+ }
+
+void CHuiCanvasImage::RemoveUser(const CHuiCanvasVisual& aUser)
+ {
+ TInt index = iActiveUsers.FindInAddressOrder(&aUser);
+
+ if (index != KErrNotFound)
+ {
+ iActiveUsers.Remove(index);
+ }
+ }
+
+TBool CHuiCanvasImage::IsUser(const CHuiCanvasVisual& aUser) const
+ {
+ TInt index = iActiveUsers.FindInAddressOrder(&aUser);
+
+ if (index != KErrNotFound)
+ {
+ return ETrue;
+ }
+ return EFalse;
+ }
+
+TBool CHuiCanvasImage::IsAnyUser() const
+ {
+ return iActiveUsers.Count() != 0;
+ }
+
+CHuiTexture* CHuiCanvasImage::Texture() const
+ {
+ return iTexture;
+ }
+
+void CHuiCanvasImage::CopyAttributes(CHuiCanvasImage& aSrc)
+ {
+ iTexture = aSrc.iTexture;
+ iGcParams = aSrc.iGcParams;
+ iLastUsed = aSrc.iLastUsed;
+ iCache = aSrc.iCache;
+
+ iActiveUsers.Reset();
+ for (TInt i=0; i < aSrc.iActiveUsers.Count(); i++)
+ {
+ iActiveUsers.Append(aSrc.iActiveUsers[i]);
+ }
+ }
+
+void CHuiCanvasImage::Reset()
+ {
+ // Reset does not delete owned items !
+ iTexture = NULL;
+ iGcParams = THuiCachedGcParams();
+ iActiveUsers.Reset();
+ }
+
+
+CHuiCanvasGraphicImage::CHuiCanvasGraphicImage() :
+ iBitmapHandle(0),
+ iMaskHandle(0),
+ iBitmap(NULL),
+ iMask(NULL),
+ iInvertedMask(EFalse),
+ iMaskOriginPoint(TPoint(0,0)),
+ iBitmapTouchCount(-1),
+ iMaskTouchCount(-1),
+ iImageSize(TSize(0,0))
+ {
+ }
+
+void CHuiCanvasGraphicImage::CopyAttributes(CHuiCanvasGraphicImage& aSrc)
+ {
+ CHuiCanvasImage::CopyAttributes(aSrc);
+ iBitmap = aSrc.iBitmap;
+ iMask = aSrc.iMask;
+ iBitmapHandle = aSrc.iBitmapHandle;
+ iMaskHandle = aSrc.iMaskHandle;
+ iInvertedMask = aSrc.iInvertedMask;
+ iMaskOriginPoint = aSrc.iMaskOriginPoint;
+ iTexture = aSrc.iTexture;
+ iBitmapTouchCount = aSrc.iBitmapTouchCount;
+ iMaskTouchCount = aSrc.iMaskTouchCount;
+ iImageSize = aSrc.iImageSize;
+
+ iSubImages.Reset();
+ for (TInt i=0; i<aSrc.iSubImages.Count();i++)
+ {
+ iSubImages.Append(aSrc.iSubImages[i]);
+ }
+ }
+
+void CHuiCanvasGraphicImage::Reset()
+ {
+ // Reset does not delete owned items !
+ CHuiCanvasImage::Reset();
+ iBitmap = NULL;
+ iMask = NULL;
+ iSubImages.Reset();
+ iBitmapHandle = 0;
+ iMaskHandle = 0;
+ iInvertedMask = EFalse;
+ iMaskOriginPoint = TPoint(0,0);
+ iTexture = NULL;
+ iBitmapTouchCount = -1;
+ iMaskTouchCount = -1;
+ iImageSize = TSize(0,0);
+ };
+
+
+
+CHuiCanvasGraphicImage::~CHuiCanvasGraphicImage()
+ {
+ delete iBitmap;
+ delete iMask;
+ for (TInt i=0;i<iSubImages.Count();i++)
+ {
+ delete iSubImages[i].iBitmap;
+ delete iSubImages[i].iMask;
+ }
+ iSubImages.Close();
+ }
+
+
+
+
+CHuiCanvasTextImage::CHuiCanvasTextImage() :
+ iText(NULL),
+ iFindTextPtr(NULL),
+ iFontHandle(0),
+ iRasterizationOffset(TPoint(0,0)),
+ iTextBoxMaxSize(TSize(KMinTInt,KMinTInt)),
+ iTextWidth(KMinTInt),
+ iBaseLineOffset(KMinTInt),
+ iTextAlign(CGraphicsContext::ELeft),
+ iMargin(0),
+ iAngle(0),
+ iUseColorModulation(EFalse),
+ iFont(NULL)
+ {
+ }
+
+void CHuiCanvasTextImage::CopyAttributes(CHuiCanvasTextImage& aSrc)
+ {
+ CHuiCanvasImage::CopyAttributes(aSrc);
+ iText = aSrc.iText;
+ iFindTextPtr = aSrc.iFindTextPtr;
+ iFontHandle = aSrc.iFontHandle;
+ iRasterizationOffset = aSrc.iRasterizationOffset;
+ iTextBoxMaxSize = aSrc.iTextBoxMaxSize;
+ iTextWidth = aSrc.iTextWidth;
+ iBaseLineOffset = aSrc.iBaseLineOffset;
+ iTextAlign = aSrc.iTextAlign;
+ iMargin = aSrc.iMargin;
+ iAngle = aSrc.iAngle;
+ iUseColorModulation = aSrc.iUseColorModulation;
+ iTextParams = aSrc.iTextParams;
+ iFont = aSrc.iFont;
+ }
+
+void CHuiCanvasTextImage::Reset()
+ {
+ // Reset does not delete owned items !
+ CHuiCanvasImage::Reset();
+ iText = NULL;
+ iFindTextPtr = NULL;
+ iFontHandle = 0,
+ iRasterizationOffset = TPoint(0,0);
+ iTextBoxMaxSize = TSize(KMinTInt,KMinTInt);
+ iTextWidth = KMinTInt;
+ iBaseLineOffset = KMinTInt;
+ iTextAlign = CGraphicsContext::ELeft;
+ iMargin = 0;
+ iAngle = 0;
+ iUseColorModulation = EFalse;
+ iFont = NULL;
+ }
+
+CHuiCanvasTextImage::~CHuiCanvasTextImage()
+ {
+ }
+
+TBool CHuiCanvasTextImage::UseColorModulation() const
+ {
+ return iUseColorModulation;
+ }
+
+NONSHARABLE_CLASS( CHuiCanvasRenderBufferImage ) : public CHuiCanvasImage
+ {
+public:
+
+ CHuiCanvasRenderBufferImage();
+
+ ~CHuiCanvasRenderBufferImage();
+
+ virtual void CopyAttributes(CHuiCanvasRenderBufferImage& aSrc);
+
+ virtual void Reset();
+
+public:
+
+ CHuiCanvasRenderBuffer* iCanvasRenderBuffer;
+ TAny* iOwner;
+ };
+
+
+CHuiCanvasRenderBufferImage::CHuiCanvasRenderBufferImage() :
+ iCanvasRenderBuffer(NULL),
+ iOwner(NULL)
+ {
+ }
+
+void CHuiCanvasRenderBufferImage::CopyAttributes(CHuiCanvasRenderBufferImage& aSrc)
+ {
+ CHuiCanvasImage::CopyAttributes(aSrc);
+ iCanvasRenderBuffer= aSrc.iCanvasRenderBuffer;
+ iOwner = aSrc.iOwner;
+ }
+
+void CHuiCanvasRenderBufferImage::Reset()
+ {
+ // Reset does not delete owned items !
+ CHuiCanvasImage::Reset();
+ iCanvasRenderBuffer = NULL;
+ iOwner = NULL;
+ }
+
+CHuiCanvasRenderBufferImage::~CHuiCanvasRenderBufferImage()
+ {
+ delete iCanvasRenderBuffer;
+ }
+
+
+NONSHARABLE_CLASS( CHuiCanvasImageRasterizer ) : public CBase
+ {
+public:
+
+ CHuiCanvasImageRasterizer();
+
+ ~CHuiCanvasImageRasterizer();
+
+ void ConstructL(TDisplayMode aPreferredMode = ENone);
+
+ TBool IsSeparateTextMaskUsed();
+
+ static CFbsBitmap* CreateMovedMaskL(CFbsBitmap& aOriginalMask, TPoint aNewTopLeftCorner);
+
+ static CFbsBitmap* CreateInvertedMaskL(CFbsBitmap& aOriginalMask);
+
+protected:
+
+ CFbsBitmap* iTempMask;
+ CFbsBitmapDevice* iTempMaskDevice;
+ CFbsBitGc* iTempMaskGc;
+
+ CFbsBitmap* iTempBitmap;
+ CFbsBitmapDevice* iTempBitmapDevice;
+ CFbsBitGc* iTempBitmapGc;
+ };
+
+CHuiCanvasImageRasterizer::CHuiCanvasImageRasterizer()
+ {
+ }
+
+CHuiCanvasImageRasterizer::~CHuiCanvasImageRasterizer()
+ {
+ delete iTempMaskGc;
+ delete iTempMaskDevice;
+ delete iTempMask;
+
+ delete iTempBitmapGc;
+ delete iTempBitmapDevice;
+ delete iTempBitmap;
+ }
+
+void CHuiCanvasImageRasterizer::ConstructL(TDisplayMode aPreferredMode)
+ {
+ iTempMask = NULL;
+ iTempMaskDevice = NULL;
+ iTempMaskGc = NULL;
+
+ iTempBitmap = NULL;
+ iTempBitmapDevice = NULL;
+ iTempBitmapGc = NULL;
+
+ // Select fastest color mode for uploading rasterized texts, we assume that EColor16MA
+ // should be best for HW accelrated rendereres (requiring least amount of conversions
+ // needed before uploading to texture memory) and EColor64K is good for
+ // bitgdi because its backbuffer is in that format.
+ //
+ // NOTE: EHuiRendererGles10 and EHuiRendererGles11 temporarely use EColor64K
+ // beacuse it looks as there are some problems with uploading 16MA
+ // mode bitmaps into multisegmented textures.
+ //
+ TDisplayMode colorMode = EColor16MA;
+ if (aPreferredMode == EGray256 &&
+ CHuiStatic::Env().Renderer() == EHuiRendererVg10)
+ {
+ colorMode = EGray256;
+ }
+ else if (aPreferredMode == EColor64K)
+ {
+ colorMode = EColor64K;
+ }
+ else if (CHuiStatic::Env().Renderer() == EHuiRendererBitgdi ||
+ CHuiStatic::Env().Renderer() == EHuiRendererGles10 ||
+ CHuiStatic::Env().Renderer() == EHuiRendererGles11)
+ {
+ colorMode = EColor64K;
+ }
+
+ iTempBitmap = new (ELeave) CFbsBitmap;
+ iTempBitmap->Create(TSize(4,4), colorMode);
+ iTempBitmapDevice = CFbsBitmapDevice::NewL(iTempBitmap);
+ User::LeaveIfError(iTempBitmapDevice->CreateContext(iTempBitmapGc));
+
+ if (colorMode != EGray256)
+ {
+ iTempMask = new (ELeave) CFbsBitmap;
+ iTempMask->Create(TSize(4,4), EGray256);
+ iTempMaskDevice = CFbsBitmapDevice::NewL(iTempMask);
+ User::LeaveIfError(iTempMaskDevice->CreateContext(iTempMaskGc));
+ }
+ }
+
+TBool CHuiCanvasImageRasterizer::IsSeparateTextMaskUsed()
+ {
+ if (iTempBitmap &&
+ iTempBitmap->DisplayMode() != EColor16MA &&
+ iTempBitmap->DisplayMode() != EColor16MAP &&
+ iTempBitmap->DisplayMode() != EGray256)
+ {
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+ }
+
+CFbsBitmap* CHuiCanvasImageRasterizer::CreateInvertedMaskL(CFbsBitmap& aOriginalMask)
+ {
+ TSize size = aOriginalMask.SizeInPixels();
+
+ CFbsBitmap* newMask = new(ELeave)CFbsBitmap;
+ CleanupStack::PushL(newMask);
+
+ CFbsBitmap* bitmap = new(ELeave)CFbsBitmap;
+ CleanupStack::PushL(bitmap);
+
+ newMask->Create(size, aOriginalMask.DisplayMode());
+ bitmap->Create(size, aOriginalMask.DisplayMode());
+
+ CFbsDevice* newMaskdevice = NULL;
+ CFbsBitGc* newMaskGc = NULL;
+
+ CFbsDevice* bitmapDevice = NULL;
+ CFbsBitGc* bitmapGc = NULL;
+
+ newMaskdevice = CFbsBitmapDevice::NewL(newMask);
+ CleanupStack::PushL(newMaskdevice);
+ User::LeaveIfError(newMaskdevice->CreateContext(newMaskGc));
+
+ bitmapDevice = CFbsBitmapDevice::NewL(bitmap);
+ CleanupStack::PushL(bitmapDevice);
+ User::LeaveIfError(bitmapDevice->CreateContext(bitmapGc));
+
+ bitmapGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
+ bitmapGc->SetPenStyle(CGraphicsContext::ESolidPen);
+ bitmapGc->SetPenColor(KRgbBlack);
+ bitmapGc->SetBrushColor(KRgbBlack);
+ bitmapGc->DrawRect(TRect(TPoint(0,0), size));
+
+ newMaskGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
+ newMaskGc->SetPenStyle(CGraphicsContext::ESolidPen);
+ newMaskGc->SetPenColor(KRgbWhite);
+ newMaskGc->SetBrushColor(KRgbWhite);
+ newMaskGc->DrawRect(TRect(TPoint(0,0), size));
+ newMaskGc->BitBltMasked(TPoint(0,0), bitmap, TRect(TPoint(0,0), size), &aOriginalMask, EFalse);
+
+ delete bitmapGc;
+ delete newMaskGc;
+
+ CleanupStack::PopAndDestroy(bitmapDevice);
+ CleanupStack::PopAndDestroy(newMaskdevice);
+ CleanupStack::PopAndDestroy(bitmap);
+ CleanupStack::Pop(newMask);
+
+ return newMask;
+ }
+
+CFbsBitmap* CHuiCanvasImageRasterizer::CreateMovedMaskL(CFbsBitmap& aOriginalMask, TPoint aNewTopLeftCorner)
+ {
+ TSize size = aOriginalMask.SizeInPixels();
+
+ CFbsBitmap* newMask = new(ELeave)CFbsBitmap;
+ CleanupStack::PushL(newMask);
+
+ newMask->Create(size, aOriginalMask.DisplayMode());
+
+ CFbsDevice* newMaskdevice = NULL;
+ CFbsBitGc* newMaskGc = NULL;
+
+ newMaskdevice = CFbsBitmapDevice::NewL(newMask);
+ CleanupStack::PushL(newMaskdevice);
+ User::LeaveIfError(newMaskdevice->CreateContext(newMaskGc));
+
+ newMaskGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
+ newMaskGc->SetPenStyle(CGraphicsContext::ESolidPen);
+ newMaskGc->SetPenColor(KRgbWhite);
+ newMaskGc->SetBrushColor(KRgbWhite);
+ newMaskGc->DrawRect(TRect(TPoint(0,0), size));
+ newMaskGc->BitBlt(TPoint(0,0), &aOriginalMask, TRect(aNewTopLeftCorner, size));
+ newMaskGc->BitBlt(aNewTopLeftCorner, &aOriginalMask, TRect(TPoint(0,0), size));
+
+ delete newMaskGc;
+ CleanupStack::PopAndDestroy(newMaskdevice);
+ CleanupStack::Pop(newMask);
+
+ return newMask;
+ }
+
+
+NONSHARABLE_CLASS( CHuiCanvasTextImageRasterizer ) : public CHuiCanvasImageRasterizer
+ {
+public:
+
+ CHuiCanvasTextImageRasterizer();
+
+ ~CHuiCanvasTextImageRasterizer();
+
+ void RasterizeL(CHuiCanvasTextImage& aTextImage);
+
+private:
+
+ TSize CalculateRasterizedTextSize(const TDesC& aText, CFont* aFont) const;
+
+ void InitL(CHuiCanvasTextImage& aTextImage, TSize& aTextsize);
+
+ void DrawL(CHuiCanvasTextImage& aTextImage, TSize& aTextsize, TPoint& aRasterizedOffset);
+
+ void UploadL(CHuiCanvasTextImage& aTextImage, TPoint& aRasterrizedOffset);
+
+private:
+
+ TInt iFontHandle;
+ CFbsBitGcFont* iFont;
+ };
+
+CHuiCanvasTextImageRasterizer::CHuiCanvasTextImageRasterizer()
+ {
+ }
+
+CHuiCanvasTextImageRasterizer::~CHuiCanvasTextImageRasterizer()
+ {
+ delete iFont;
+ }
+
+TSize CHuiCanvasTextImageRasterizer::CalculateRasterizedTextSize(const TDesC& aText, CFont* aFont) const
+ {
+ CFont::TMeasureTextInput input;
+ input.iFlags = CFont::TMeasureTextInput::EFVisualOrder;
+ CFont::TMeasureTextOutput output;
+
+ TInt textAdvance = aFont->MeasureText( aText, &input, &output );
+
+ TRect bounds = output.iBounds;
+ bounds.iTl.iX = Min(bounds.iTl.iX, 0);
+ bounds.iBr.iX = Max(bounds.iBr.iX, textAdvance);
+
+ TSize textSize = TSize(bounds.Width(), aFont->FontMaxHeight());
+
+ const CAknLayoutFont* layoutFont = 0;
+
+ if (CCoeEnv::Static())
+ {
+ layoutFont = CAknLayoutFont::AsCAknLayoutFontOrNull( aFont );
+ }
+
+ if ( layoutFont )
+ {
+ textSize.iHeight = aFont->HeightInPixels();
+ TInt textPaneHeight = layoutFont->TextPaneHeight();
+ TInt textPaneTopToBaseline = layoutFont->TextPaneTopToBaseline();
+
+ textSize.iHeight += textPaneHeight - textPaneTopToBaseline;
+ textSize.iHeight += KHuiFontVerticalShiftInPixels;
+ }
+ else
+ {
+ textSize.iHeight = Max(textSize.iHeight, aFont->HeightInPixels());
+ textSize.iHeight += 3; // the best approximation - fails on big (>=72) fonts
+ }
+
+ return textSize;
+ }
+
+
+void CHuiCanvasTextImageRasterizer::RasterizeL(CHuiCanvasTextImage& aTextImage)
+ {
+ TPoint rasterizedOffset(0, 0);
+
+ if (aTextImage.iFontHandle && (iFontHandle != aTextImage.iFontHandle))
+ {
+ delete iFont;
+ iFont = NULL;
+
+ // the font might have been duplicated earlier in order to
+ // find out whether it is an outline font or not. As the CHuiCanvasTextImage
+ // does not own the font pointer by it's member iFont, just copy the pointer
+ // to the instance of this class..
+ if (aTextImage.iFont)
+ {
+ iFont = aTextImage.iFont;
+ }
+ else
+ {
+ // Font is cached as pointer because next text may same font and in that case
+ // we are much faster as there is no need to do font duplication again.
+ iFont = new (ELeave) CFbsBitGcFont();
+ iFontHandle = aTextImage.iFontHandle;
+ TInt fontDuplicateErrorCode = iFont->Duplicate(iFontHandle);
+
+ if (fontDuplicateErrorCode)
+ {
+ // Invalid handle which would panic inside fbsbitgc
+ iFontHandle = 0;
+ delete iFont;
+ iFont = NULL;
+ aTextImage.iFont = NULL;
+ }
+ else
+ {
+ // we need a reference to the font in CHuiCanvasTextImage aswell..
+ aTextImage.iFont = iFont;
+ }
+ }
+ }
+
+ if (iFont)
+ {
+ TSize textSize = TSize(0,0);
+ TInt textAscent = 0;
+
+ // If no max size is provided, we need to approximate the needed texture size.
+ if (aTextImage.iTextBoxMaxSize == TSize(KMinTInt,KMinTInt))
+ {
+ textSize = CalculateRasterizedTextSize(*aTextImage.iText, iFont);
+
+ // To get most closest values for the font metrics we could try to cast
+ // font into aknlayoutfont, but that does not seem to work when font is
+ // duplicated trough handle. This solution is not accurate and results slightly
+ // too large textures but avoids text clipping.
+ TReal32 height = textSize.iHeight;
+ textSize.iHeight = height * 1.2;
+ textAscent = height * 0.9;
+
+ // If rotated 90 degress, then flip width and heigths
+ if (aTextImage.iAngle == 90 || aTextImage.iAngle == -90)
+ {
+ TSize horizontalTextSize = textSize;
+ textSize.iWidth = horizontalTextSize.iHeight;
+ textSize.iHeight = horizontalTextSize.iWidth;
+ }
+
+ // Since we modify the actual point where drawing is to happen
+ // (so that image size gets minimized), we use rasterizedOffset to specify
+ // offset we have used. That offset needs to be used when image of the text
+ // is to be drawn because with these coordinates text goes exactly where it ´
+ // is supposed to go.
+ if (aTextImage.iAngle == 90)
+ {
+ // Rotated clockwise
+ rasterizedOffset.iX = textSize.iWidth-textAscent;
+ }
+ else if (aTextImage.iAngle == -90)
+ {
+ // Rotated anti clockwise
+ rasterizedOffset.iX = textAscent;
+ // Drawing happens upwards
+ rasterizedOffset.iY = textSize.iHeight;
+ }
+ else
+ {
+ // No rotation, just drawn lower
+ rasterizedOffset.iY = textAscent;
+ }
+ }
+ else
+ {
+ // Clipping text box is provided, much easier this way.
+ textSize = aTextImage.iTextBoxMaxSize;
+ }
+
+ // Setup gc parameters
+ InitL(aTextImage, textSize);
+
+ // Draw the text
+ DrawL(aTextImage, textSize, rasterizedOffset);
+ }
+
+ // Upload content
+ UploadL(aTextImage, rasterizedOffset);
+
+ }
+
+void CHuiCanvasTextImageRasterizer::InitL(CHuiCanvasTextImage& aTextImage, TSize& aTextsize)
+ {
+ TFontUnderline underline = (TFontUnderline)aTextImage.iGcParams.iUnderline;
+ TFontStrikethrough strikethrough = (TFontStrikethrough)aTextImage.iGcParams.iStrikethrough;
+ CGraphicsContext::TBrushStyle brushstyle = (CGraphicsContext::TBrushStyle)aTextImage.iGcParams.iBrushStyle;
+ CGraphicsContext::TPenStyle penstyle = (CGraphicsContext::TPenStyle)aTextImage.iGcParams.iPenStyle;
+ TInt shadowmode = aTextImage.iGcParams.iShadowMode; // TODO: Is this even needed for texts ?
+ TBool outlinefont = iFont->FontSpecInTwips().iFontStyle.IsEffectOn(FontEffect::EOutline);
+ if (IsSeparateTextMaskUsed())
+ {
+ iTempMask->Resize(aTextsize);
+ iTempMaskDevice->Resize(aTextsize);
+
+ delete iTempMaskGc;
+ iTempMaskGc = NULL;
+ User::LeaveIfError(iTempMaskDevice->CreateContext(iTempMaskGc));
+
+ // Mask bitmap, this defines the shape of the text.
+ iTempMaskGc->SetBrushColor(KRgbBlack);
+ iTempMaskGc->Clear();
+ iTempMaskGc->SetPenColor(KRgbWhite);
+
+ // We dont call the UseFont() variant with handle param because it is slower
+ iTempMaskGc->UseFont(iFont);
+
+ // Set correct gc settings
+ iTempMaskGc->SetPenStyle(penstyle);
+ iTempMaskGc->SetBrushStyle(brushstyle);
+ iTempMaskGc->SetUnderlineStyle(underline);
+ iTempMaskGc->SetStrikethroughStyle(strikethrough);
+ iTempMaskGc->SetShadowMode(shadowmode);
+ }
+
+ iTempBitmap->Resize(aTextsize);
+ iTempBitmapDevice->Resize(aTextsize);
+
+ delete iTempBitmapGc;
+ iTempBitmapGc = NULL;
+ User::LeaveIfError(iTempBitmapDevice->CreateContext(iTempBitmapGc));
+
+ if (IsSeparateTextMaskUsed())
+ {
+ // Just fill with correct color, text shape comes from mask
+ if (KHuiCanvasTextUseColorModulation)
+ {
+ iTempBitmapGc->SetPenColor(KRgbWhite);
+ }
+ else
+ {
+ iTempBitmapGc->SetPenColor(aTextImage.iGcParams.iPenColor);
+ }
+
+ iTempBitmapGc->SetBrushColor(aTextImage.iGcParams.iBrushColor);
+ iTempBitmapGc->Clear();
+ }
+ else
+ {
+ // First clear
+ TRgb clearColor(KRgbBlack);
+ clearColor.SetAlpha(0);
+ iTempBitmapGc->SetPenColor(clearColor);
+ iTempBitmapGc->SetBrushColor(clearColor);
+ if (iTempBitmap->DisplayMode() == EColor16MA)
+ {
+ iTempBitmapGc->SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
+ }
+ else
+ {
+ iTempBitmapGc->SetDrawMode(CGraphicsContext::EDrawModePEN);
+ }
+
+ iTempBitmapGc->Clear();
+
+ // Set correct gc settings
+ if (!outlinefont && KHuiCanvasTextUseColorModulation)
+ {
+ iTempBitmapGc->SetPenColor(KRgbWhite);
+ }
+ else
+ {
+ iTempBitmapGc->SetPenColor(aTextImage.iGcParams.iPenColor);
+ iTempBitmapGc->SetBrushColor(aTextImage.iGcParams.iBrushColor);
+ }
+
+ iTempBitmapGc->SetPenStyle(penstyle);
+ if (!outlinefont)
+ {
+ iTempBitmapGc->SetBrushStyle( CGraphicsContext::ENullBrush );
+ }
+ else
+ {
+ iTempBitmapGc->SetBrushStyle( brushstyle );
+ }
+
+ iTempBitmapGc->SetUnderlineStyle(underline);
+ iTempBitmapGc->SetStrikethroughStyle(strikethrough);
+ iTempBitmapGc->SetShadowMode(shadowmode);
+ }
+
+ // We dont call the UseFont() variant with handle param because it is slower
+ iTempBitmapGc->UseFont(iFont);
+
+ // Are we using color modulation, store info to entry
+ aTextImage.iUseColorModulation = outlinefont ? EFalse : KHuiCanvasTextUseColorModulation;
+
+ // Debug, enable this to see texture outlines.
+ //iTempMaskGc->DrawRect(TRect(TPoint(0,0), textSize));
+ }
+
+void CHuiCanvasTextImageRasterizer::DrawL(CHuiCanvasTextImage& aTextImage, TSize& aTextsize, TPoint& aRasterizedOffset)
+ {
+#ifdef SYMBIAN_BUILD_GCE
+ CGraphicsContext::TTextParameters gcTextParams = *(CGraphicsContext::TTextParameters*)& aTextImage.iTextParams;
+#endif
+ // Based on supplied params, select the approprite DrawText variant.
+ TBool up = (aTextImage.iAngle == -90);
+ if (aTextImage.iTextBoxMaxSize != TSize(KMinTInt,KMinTInt))
+ {
+ if (aTextImage.iBaseLineOffset != KMinTInt)
+ {
+ CGraphicsContext::TTextAlign align = (CGraphicsContext::TTextAlign) aTextImage.iTextAlign;
+
+ if (aTextImage.iTextWidth != KMinTInt)
+
+ {
+ if (aTextImage.iAngle == 0)
+ {
+ if (IsSeparateTextMaskUsed())
+ {
+ iTempMaskGc->DrawText(*aTextImage.iText,
+#ifdef SYMBIAN_BUILD_GCE
+ &gcTextParams,
+#endif
+ TRect(TPoint(0,0), aTextsize), aTextImage.iBaseLineOffset, aTextImage.iTextWidth, align, aTextImage.iMargin);
+ }
+ else
+ {
+ // No need to draw separate mask, iTempBitmapGc is using EDrawModeWriteAlpha mode
+ }
+
+ iTempBitmapGc->DrawText(*aTextImage.iText,
+#ifdef SYMBIAN_BUILD_GCE
+ &gcTextParams,
+#endif
+ TRect(TPoint(0,0), aTextsize), aTextImage.iBaseLineOffset, aTextImage.iTextWidth, align, aTextImage.iMargin);
+ }
+ else
+ {
+ if (IsSeparateTextMaskUsed())
+ {
+ iTempMaskGc->DrawTextVertical(*aTextImage.iText,
+#ifdef SYMBIAN_BUILD_GCE
+ &gcTextParams,
+#endif
+ TRect(TPoint(0,0), aTextsize), aTextImage.iBaseLineOffset, aTextImage.iTextWidth, up, align, aTextImage.iMargin);
+ }
+ else
+ {
+ // No need to draw separate mask, iTempBitmapGc is using EDrawModeWriteAlpha mode
+ }
+ iTempBitmapGc->DrawTextVertical(*aTextImage.iText,
+#ifdef SYMBIAN_BUILD_GCE
+ &gcTextParams,
+#endif
+ TRect(TPoint(0,0), aTextsize), aTextImage.iBaseLineOffset, aTextImage.iTextWidth, up, align, aTextImage.iMargin);
+ }
+ }
+ else
+ {
+ if (aTextImage.iAngle == 0)
+ {
+ if (IsSeparateTextMaskUsed())
+ {
+ iTempMaskGc->DrawText(*aTextImage.iText,
+#ifdef SYMBIAN_BUILD_GCE
+ &gcTextParams,
+#endif
+ TRect(TPoint(0,0), aTextsize), aTextImage.iBaseLineOffset, align, aTextImage.iMargin);
+ }
+ else
+ {
+ // No need to draw separate mask, iTempBitmapGc is using EDrawModeWriteAlpha mode
+ }
+ iTempBitmapGc->DrawText(*aTextImage.iText,
+#ifdef SYMBIAN_BUILD_GCE
+ &gcTextParams,
+#endif
+ TRect(TPoint(0,0), aTextsize), aTextImage.iBaseLineOffset, align, aTextImage.iMargin);
+ }
+ else
+ {
+ if (IsSeparateTextMaskUsed())
+ {
+ iTempMaskGc->DrawTextVertical(*aTextImage.iText,
+#ifdef SYMBIAN_BUILD_GCE
+ &gcTextParams,
+#endif
+ TRect(TPoint(0,0), aTextsize), aTextImage.iBaseLineOffset, up, align, aTextImage.iMargin);
+ }
+ else
+ {
+ // No need to draw separate mask, iTempBitmapGc is using EDrawModeWriteAlpha mode
+ }
+ iTempBitmapGc->DrawTextVertical(*aTextImage.iText,
+#ifdef SYMBIAN_BUILD_GCE
+ &gcTextParams,
+#endif
+ TRect(TPoint(0,0), aTextsize), aTextImage.iBaseLineOffset, up, align, aTextImage.iMargin);
+ }
+ }
+ }
+ else
+ {
+ if (aTextImage.iAngle == 0)
+ {
+ if (IsSeparateTextMaskUsed())
+ {
+ iTempMaskGc->DrawText(*aTextImage.iText,
+#ifdef SYMBIAN_BUILD_GCE
+ &gcTextParams,
+#endif
+ TRect(TPoint(0,0), aTextsize) );
+ }
+ else
+ {
+ // No need to draw separate mask, iTempBitmapGc is using EDrawModeWriteAlpha mode
+ }
+
+ iTempBitmapGc->DrawText(*aTextImage.iText,
+#ifdef SYMBIAN_BUILD_GCE
+ &gcTextParams,
+#endif
+ TRect(TPoint(0,0), aTextsize));
+ }
+ else
+ {
+ if (IsSeparateTextMaskUsed())
+ {
+ iTempMaskGc->DrawTextVertical(*aTextImage.iText,
+#ifdef SYMBIAN_BUILD_GCE
+ &gcTextParams,
+#endif
+ TRect(TPoint(0,0), aTextsize), up );
+ }
+ else
+ {
+ // No need to draw separate mask, iTempBitmapGc is using EDrawModeWriteAlpha mode
+ }
+
+ iTempBitmapGc->DrawTextVertical(*aTextImage.iText,
+#ifdef SYMBIAN_BUILD_GCE
+ &gcTextParams,
+#endif
+ TRect(TPoint(0,0), aTextsize), up);
+ }
+ }
+ }
+ else
+ {
+ if (aTextImage.iAngle == 0)
+ {
+ if (IsSeparateTextMaskUsed())
+ {
+ iTempMaskGc->DrawText(*aTextImage.iText,
+#ifdef SYMBIAN_BUILD_GCE
+ &gcTextParams,
+#endif
+ aRasterizedOffset);
+ }
+ else
+ {
+ // No need to draw separate mask, iTempBitmapGc is using EDrawModeWriteAlpha mode
+ }
+
+ iTempBitmapGc->DrawText(*aTextImage.iText,
+#ifdef SYMBIAN_BUILD_GCE
+ &gcTextParams,
+#endif
+ aRasterizedOffset);
+ }
+ else
+ {
+ if (IsSeparateTextMaskUsed())
+ {
+ iTempMaskGc->DrawTextVertical(*aTextImage.iText,
+#ifdef SYMBIAN_BUILD_GCE
+ &gcTextParams,
+#endif
+ aRasterizedOffset, up);
+ }
+ else
+ {
+ // No need to draw separate mask, iTempBitmapGc is using EDrawModeWriteAlpha mode
+ }
+
+ iTempBitmapGc->DrawTextVertical(*aTextImage.iText,
+#ifdef SYMBIAN_BUILD_GCE
+ &gcTextParams,
+#endif
+ aRasterizedOffset, up);
+ }
+ }
+ }
+
+void CHuiCanvasTextImageRasterizer::UploadL(CHuiCanvasTextImage& aTextImage, TPoint& aRasterizedOffset)
+ {
+ // Upload bitmap content...this may be slow depending on used HW acceleration !
+
+ TSize colorBitmapSize = iTempBitmap->SizeInPixels();
+ TSize maskBitmapSize = IsSeparateTextMaskUsed() ? iTempMask->SizeInPixels() : colorBitmapSize;
+ CFbsBitmap* textColorBitmap = iTempBitmap;
+ CFbsBitmap* textMaskBitmap = IsSeparateTextMaskUsed() ? iTempMask : NULL;
+
+
+ if (maskBitmapSize.iWidth > 0 &&
+ maskBitmapSize.iHeight > 0 &&
+ colorBitmapSize.iWidth > 0 &&
+ colorBitmapSize.iHeight > 0)
+ {
+ // TODO: For BitGdi it might be good to use direct upload, but it would require changes such as
+ // making new textColorBitmap, textMaskBitmap everytime.
+ THuiTextureUploadFlags uploadFlags = THuiTextureUploadFlags(EHuiTextureUploadFlagDoNotRetainResolution | EHuiTextureUploadFlagRetainColorDepth);
+
+#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
+ TTime startTime;
+ startTime.UniversalTime();
+#endif
+
+ aTextImage.iRasterizationOffset = aRasterizedOffset;
+
+ CHuiTexture* texture = aTextImage.iTexture;
+ texture->UploadL(*textColorBitmap, textMaskBitmap, uploadFlags);
+
+#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
+ TTime endTime;
+ endTime.UniversalTime();
+ TInt uploadTimeInMilliSeconds = endTime.MicroSecondsFrom( startTime ).Int64()/1000;
+ RDebug::Print(_L(">>> CHuiCanvasTextImageRasterizer::UpdateCachedTextL: Upload of %ix%i %S took %i ms"),
+ texture->Size().iWidth,
+ texture->Size().iHeight,
+ aTextImage.iText,
+ uploadTimeInMilliSeconds);
+#endif
+ }
+ }
+
+
+NONSHARABLE_CLASS( CHuiCanvasGraphicImageRasterizer ) : public CHuiCanvasImageRasterizer
+ {
+public:
+
+ CHuiCanvasGraphicImageRasterizer();
+
+ ~CHuiCanvasGraphicImageRasterizer();
+
+ void ConstructL(TBool aUseGray256 = EFalse);
+
+ void RasterizeL(CHuiCanvasGraphicImage& aImage);
+
+private:
+ };
+
+CHuiCanvasGraphicImageRasterizer::CHuiCanvasGraphicImageRasterizer()
+ {
+ }
+
+CHuiCanvasGraphicImageRasterizer::~CHuiCanvasGraphicImageRasterizer()
+ {
+ }
+
+void CHuiCanvasGraphicImageRasterizer::ConstructL(TBool /*aUseGray256*/)
+ {
+ }
+
+void CHuiCanvasGraphicImageRasterizer::RasterizeL(CHuiCanvasGraphicImage& aImage)
+ {
+ CFbsBitmap* bitmap = NULL;
+ CFbsBitmap* mask = NULL;
+
+ TInt bitmapTouchCount = KHuiInitialBitmapTouchCount;
+ TInt maskTouchCount = KHuiInitialBitmapTouchCount;
+
+#ifdef SYMBIAN_BUILD_GCE
+ TBool volatileBitmapOrMask = EFalse;
+#else
+ TBool volatileBitmapOrMask = ETrue;
+#endif
+
+ TBool originalMaskUsed = ETrue;
+
+
+ TInt bitmapHandle = aImage.iBitmapHandle;
+ TInt maskHandle = aImage.iMaskHandle;
+ TBool invertMask = aImage.iInvertedMask;
+ TPoint maskOriginPoint = aImage.iMaskOriginPoint;
+
+ if (!bitmapHandle)
+ {
+ return;
+ }
+
+ // Lets see if we have already cached the pointer...
+ if (aImage.iBitmap)
+ {
+ // ...yes lets use it
+ bitmap = aImage.iBitmap;
+ }
+ else
+ {
+ // ...no, so we need to duplicate the handle
+ bitmap = new(ELeave)CFbsBitmap;
+ bitmap->Duplicate(bitmapHandle);
+ if (bitmap)
+ {
+ if (KHuiCanvasKeepBitmapPointer)
+ {
+ aImage.iBitmap = bitmap;
+ }
+ else
+ {
+ CleanupStack::PushL(bitmap);
+ }
+ }
+
+ }
+
+#ifdef SYMBIAN_BUILD_GCE
+ if (bitmap)
+ {
+ bitmapTouchCount = bitmap->TouchCount();
+ volatileBitmapOrMask |= bitmap->IsVolatile();
+ }
+#endif
+
+ // Mask is optional
+ if (maskHandle)
+ {
+ // Lets see if we have already cached the pointer...
+ if (aImage.iMask)
+ {
+ // ...yes lets use it
+ mask = aImage.iMask;
+ }
+ else
+ {
+ // ...no, so we need to duplicate the handle
+ mask = new(ELeave)CFbsBitmap;
+ mask->Duplicate(maskHandle);
+ if (mask)
+ {
+ if (KHuiCanvasKeepBitmapPointer)
+ {
+ aImage.iMask = mask;
+ }
+ else
+ {
+ CleanupStack::PushL(mask);
+ }
+ }
+ }
+
+#ifdef SYMBIAN_BUILD_GCE
+ if (mask)
+ {
+ maskTouchCount = mask->TouchCount();
+ volatileBitmapOrMask |= mask->IsVolatile();
+ }
+#endif
+
+ // If mask is defined not to be inverted,
+ // we must invert it because toolkit assumes they are always inverted. Huh.
+#ifdef __NVG
+ // Inverting masks is done ONLY for non-extended bitmaps!
+ if (bitmap->ExtendedBitmapType() == KNullUid) // => Bitmap isn't extended
+ {
+#endif
+ if (invertMask && mask->DisplayMode() == EGray2)
+ {
+ CFbsBitmap* invertedMask = CreateInvertedMaskL(*mask);
+
+ // If we are not using stored pointer, delete it
+ if (mask != aImage.iMask)
+ {
+ CleanupStack::PopAndDestroy(mask);
+ }
+
+ mask = invertedMask;
+ CleanupStack::PushL(mask);
+ originalMaskUsed = EFalse;
+ }
+
+ // Upload expects mask to begin always at TPoint(0,0), so if mask
+ // offset is defined we re-create mask with the given new
+ // offset. Note that it might be a good idea to combine this op
+ // with mask inversion op, but we assume that these are not really used
+ // very often, even more rarely together.
+ if (maskOriginPoint != TPoint(0,0))
+ {
+ CFbsBitmap* movedMask = CreateMovedMaskL(*mask, maskOriginPoint);
+
+ // If we are not using stored pointer, delete it
+ if (mask != aImage.iMask)
+ {
+ CleanupStack::PopAndDestroy(mask);
+ }
+ mask = movedMask;
+ CleanupStack::PushL(mask);
+ originalMaskUsed = EFalse;
+ }
+#ifdef __NVG
+ }
+#endif
+ }
+
+ // Bitmap has changed, must be updated ?
+ TBool touchCountChanged = EFalse;
+ touchCountChanged |= volatileBitmapOrMask;
+ touchCountChanged |= (aImage.iBitmapTouchCount != bitmapTouchCount);
+ touchCountChanged |= (aImage.iMaskTouchCount != maskTouchCount);
+
+ // Is touch count check enabled ?
+ TBool touchCountCheckEnabled = CHuiStatic::Env().CanvasTextureCache().IsTouchCountCheckEnabled();
+
+ // Has it old content at all ?
+ TBool hasContent = aImage.iTexture->HasContent();
+
+ if (!hasContent || (touchCountCheckEnabled && touchCountChanged))
+ {
+ // Upload bitmap content...this may be slow depending on used HW acceleration !
+ if (bitmap->SizeInPixels().iWidth > 0 &&
+ bitmap->SizeInPixels().iHeight > 0 &&
+ (!mask || (mask->SizeInPixels().iWidth > 0 && mask->SizeInPixels().iHeight)))
+ {
+ // EHuiTextureUploadFlagDoNotRetainResolution should be removed when
+ // texturecoordinates with segmented textures work.
+ // This flag causes ugly scaling to happen with small textures.
+ THuiTextureUploadFlags uploadFlags = THuiTextureUploadFlags(EHuiTextureUploadFlagDoNotRetainResolution | EHuiTextureUploadFlagRetainColorDepth);
+
+#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
+ TTime startTime;
+ startTime.UniversalTime();
+#endif
+
+ CHuiTexture* texture = aImage.iTexture;
+ texture->UploadL(*bitmap, mask, uploadFlags);
+
+#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
+ TTime endTime;
+ endTime.UniversalTime();
+ TInt uploadTimeInMilliSeconds = endTime.MicroSecondsFrom( startTime ).Int64()/1000;
+
+ if (volatileBitmapOrMask)
+ {
+ RDebug::Print(_L(">>> CHuiCanvasGraphicImageRasterizer::UpdateCachedImageL: Reason for uploading is volatileBitmapOrMask"));
+ }
+
+ if (aImage.iBitmapTouchCount != bitmapTouchCount)
+ {
+ RDebug::Print(_L(">>> CHuiCanvasGraphicImageRasterizer::UpdateCachedImageL: Reason for uploading is iBitmapTouchCount %i, old was %i "), bitmapTouchCount, aImage.iBitmapTouchCount);
+ }
+
+ if (aImage.iMaskTouchCount != maskTouchCount)
+ {
+ RDebug::Print(_L(">>> CHuiCanvasGraphicImageRasterizer::UpdateCachedImageL: Reason for uploading is iMaskTouchCount %i, old was %i "), maskTouchCount, aImage.iMaskTouchCount);
+ }
+
+ RDebug::Print(_L(">>> CHuiCanvasGraphicImageRasterizer::UpdateCachedImageL: Upload of %ix%i %i+%i took %i ms"),
+ texture->Size().iWidth,
+ texture->Size().iHeight,
+ aImage.iBitmapHandle,
+ aImage.iMaskHandle,
+ uploadTimeInMilliSeconds);
+#endif
+ }
+
+#ifdef SYMBIAN_BUILD_GCE
+ // Texture upload itself must not modify bitmap or mask touch count.
+ // Otherwise, it's impossible to detect client data access
+ // (since there is not necessarily any synchronisation between client & alf).
+
+ aImage.iBitmapTouchCount = bitmapTouchCount;
+ aImage.iMaskTouchCount = maskTouchCount;
+#endif
+ }
+ else
+ {
+ if (touchCountChanged && !touchCountCheckEnabled)
+ {
+#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
+ RDebug::Print(_L(">>> CHuiCanvasGraphicImageRasterizer::UpdateCachedImageL: skipping uploading because touchcount check is disabled"));
+#endif
+ }
+ }
+
+ // If we are not using stored pointer, delete it
+ if (mask && (mask != aImage.iMask))
+ {
+ CleanupStack::PopAndDestroy(mask);
+ mask = NULL;
+ }
+
+ // If we are not using stored pointer, delete it
+ if (bitmap && (bitmap != aImage.iBitmap))
+ {
+ CleanupStack::PopAndDestroy(bitmap);
+ bitmap = NULL;
+ }
+ }
+
+
+
+NONSHARABLE_CLASS( CHuiCanvasCombinedGraphicImageRasterizer ) : public CHuiCanvasImageRasterizer
+ {
+public:
+
+ CHuiCanvasCombinedGraphicImageRasterizer();
+
+ ~CHuiCanvasCombinedGraphicImageRasterizer();
+
+ void RasterizeL(CHuiCanvasGraphicImage& aImage);
+
+private:
+
+ void InitL(CHuiCanvasGraphicImage& aImage);
+
+ void DrawL(CHuiCanvasGraphicImage& aImage);
+
+ void UploadL(CHuiCanvasGraphicImage& aImage);
+
+ };
+
+CHuiCanvasCombinedGraphicImageRasterizer::CHuiCanvasCombinedGraphicImageRasterizer()
+ {
+ }
+
+CHuiCanvasCombinedGraphicImageRasterizer::~CHuiCanvasCombinedGraphicImageRasterizer()
+ {
+ }
+
+void CHuiCanvasCombinedGraphicImageRasterizer::RasterizeL(CHuiCanvasGraphicImage& aImage)
+ {
+ // First check the bitmaps
+ TBool bitmapsChanged = EFalse;
+ for (TInt i=0; i<aImage.iSubImages.Count(); i++)
+ {
+ // Lets see if we have already cached the pointer...
+ if (!aImage.iSubImages[i].iBitmap)
+ {
+ // ...no we must duplicate handle
+ if (aImage.iSubImages[i].iBitmapHandle)
+ {
+ aImage.iSubImages[i].iBitmap = new (ELeave) CFbsBitmap;
+ aImage.iSubImages[i].iBitmap->Duplicate(aImage.iSubImages[i].iBitmapHandle);
+ }
+ }
+
+ if (!aImage.iSubImages[i].iMask)
+ {
+ // Lets see if we have already cached the pointer...
+ if (aImage.iSubImages[i].iMaskHandle)
+ {
+ aImage.iSubImages[i].iMask = new (ELeave) CFbsBitmap;
+ aImage.iSubImages[i].iMask->Duplicate(aImage.iSubImages[i].iMaskHandle);
+ }
+ }
+
+ if (aImage.iSubImages[i].iBitmap)
+ {
+ bitmapsChanged |= (aImage.iSubImages[i].iBitmapTouchCount != aImage.iSubImages[i].iBitmap->TouchCount());
+ }
+
+ if (aImage.iSubImages[i].iMask)
+ {
+ bitmapsChanged |= (aImage.iSubImages[i].iMaskTouchCount != aImage.iSubImages[i].iMask->TouchCount());
+ }
+ }
+
+ if (bitmapsChanged)
+ {
+ InitL(aImage);
+
+ DrawL(aImage);
+
+ UploadL(aImage);
+
+ // Touch counts updated after upload in case upload changes the count ?
+ for (TInt i=0; i<aImage.iSubImages.Count(); i++)
+ {
+ if (aImage.iSubImages[i].iBitmap)
+ aImage.iSubImages[i].iBitmapTouchCount = aImage.iSubImages[i].iBitmap->TouchCount();
+
+ if (aImage.iSubImages[i].iMask)
+ aImage.iSubImages[i].iMaskTouchCount = aImage.iSubImages[i].iMask->TouchCount();
+ }
+ }
+
+ if (!KHuiCanvasKeepBitmapPointer)
+ {
+ for (TInt i=0; i<aImage.iSubImages.Count(); i++)
+ {
+ delete aImage.iSubImages[i].iBitmap;
+ aImage.iSubImages[i].iBitmap = NULL;
+
+ delete aImage.iSubImages[i].iMask;
+ aImage.iSubImages[i].iMask = NULL;
+ }
+ }
+ }
+
+
+void CHuiCanvasCombinedGraphicImageRasterizer::InitL(CHuiCanvasGraphicImage& aImage)
+ {
+ if (IsSeparateTextMaskUsed())
+ {
+ iTempMask->Resize(aImage.iImageSize);
+ iTempMaskDevice->Resize(aImage.iImageSize);
+
+ delete iTempMaskGc;
+ iTempMaskGc = NULL;
+ User::LeaveIfError(iTempMaskDevice->CreateContext(iTempMaskGc));
+
+ iTempMaskGc->Reset();
+ iTempMaskGc->SetBrushColor(KRgbBlack);
+ iTempMaskGc->Clear();
+ iTempMaskGc->SetPenColor(KRgbWhite);
+ }
+
+ iTempBitmap->Resize(aImage.iImageSize);
+ iTempBitmapDevice->Resize(aImage.iImageSize);
+
+ delete iTempBitmapGc;
+ iTempBitmapGc = NULL;
+ User::LeaveIfError(iTempBitmapDevice->CreateContext(iTempBitmapGc));
+
+ if (IsSeparateTextMaskUsed())
+ {
+ TRgb clearColor(KRgbWhite);
+ clearColor.SetAlpha(0);
+ iTempBitmapGc->SetPenColor(clearColor);
+ iTempBitmapGc->SetBrushColor(clearColor);
+ iTempBitmapGc->SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
+ iTempBitmapGc->Clear();
+ iTempBitmapGc->SetPenColor(KRgbWhite);
+
+ iTempMaskGc->SetPenColor(clearColor);
+ iTempMaskGc->SetBrushColor(clearColor);
+ iTempMaskGc->SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
+ iTempMaskGc->Clear();
+ iTempMaskGc->SetPenColor(KRgbWhite);
+ }
+ else
+ {
+ // First clear
+ TRgb clearColor(KRgbWhite);
+ clearColor.SetAlpha(0);
+ iTempBitmapGc->SetPenColor(clearColor);
+ iTempBitmapGc->SetBrushColor(clearColor);
+ iTempBitmapGc->SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
+ iTempBitmapGc->Clear();
+ iTempBitmapGc->SetPenColor(KRgbWhite);
+ }
+ }
+
+void CHuiCanvasCombinedGraphicImageRasterizer::DrawL(CHuiCanvasGraphicImage& aImage)
+ {
+ for (TInt i=0; i<aImage.iSubImages.Count(); i++)
+ {
+ CFbsBitmap* bitmap = aImage.iSubImages[i].iBitmap;
+ CFbsBitmap* mask = aImage.iSubImages[i].iMask;
+ TPoint point = aImage.iSubImages[i].iCombinedBitmapPoint;
+
+ if (bitmap)
+ {
+ if (IsSeparateTextMaskUsed())
+ {
+ TRect sourceRect = TRect(TPoint(0,0), bitmap->SizeInPixels());
+ if (bitmap)
+ {
+ iTempBitmapGc->BitBlt(point, bitmap);
+ }
+ if (mask)
+ {
+ iTempMaskGc->BitBlt(point, mask);
+ }
+ }
+ else
+ {
+ TRect sourceRect = TRect(TPoint(0,0), bitmap->SizeInPixels());
+ if (mask)
+ {
+ TBool invertMask = (mask->DisplayMode() == EGray256);
+ iTempBitmapGc->BitBltMasked(point, bitmap, sourceRect, mask, invertMask);
+ }
+ else
+ {
+ iTempBitmapGc->BitBlt(point, bitmap);
+ }
+ }
+ }
+ }
+ }
+
+void CHuiCanvasCombinedGraphicImageRasterizer::UploadL(CHuiCanvasGraphicImage& aImage)
+ {
+ CFbsBitmap* mask = IsSeparateTextMaskUsed() ? iTempMask : NULL;
+
+ // Upload bitmap content...this may be slow depending on used HW acceleration !
+ if (iTempBitmap->SizeInPixels().iWidth > 0 &&
+ iTempBitmap->SizeInPixels().iHeight > 0 &&
+ (!mask || (mask->SizeInPixels().iWidth > 0 && mask->SizeInPixels().iHeight)))
+ {
+ // EHuiTextureUploadFlagDoNotRetainResolution should be removed when
+ // texturecoordinates with segmented textures work.
+ // This flag causes ugly scaling to happen with small textures.
+ THuiTextureUploadFlags uploadFlags = THuiTextureUploadFlags(EHuiTextureUploadFlagDoNotRetainResolution | EHuiTextureUploadFlagRetainColorDepth);
+
+#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
+ TTime startTime;
+ startTime.UniversalTime();
+#endif
+
+ CHuiTexture* texture = aImage.iTexture;
+ texture->UploadL(*iTempBitmap, mask, uploadFlags);
+
+#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
+ TTime endTime;
+ endTime.UniversalTime();
+ TInt uploadTimeInMilliSeconds = endTime.MicroSecondsFrom( startTime ).Int64()/1000;
+
+ RDebug::Print(_L(">>> CHuiCanvasCombinedGraphicImageRasterizer::UploadCombinedImageL: Upload of %ix%i %i+%i took %i ms"),
+ texture->Size().iWidth,
+ texture->Size().iHeight,
+ aImage.iBitmapHandle,
+ aImage.iMaskHandle,
+ uploadTimeInMilliSeconds);
+#endif
+ }
+ }
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TInt ImageTimeOrderFunc(const CHuiCanvasGraphicImage& aFirst, const CHuiCanvasGraphicImage& aSecond)
+ {
+ if (aFirst.iLastUsed < aSecond.iLastUsed)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iLastUsed > aSecond.iLastUsed)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TInt TextTimeOrderFunc(const CHuiCanvasTextImage& aFirst, const CHuiCanvasTextImage& aSecond)
+ {
+ if (aFirst.iLastUsed < aSecond.iLastUsed)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iLastUsed > aSecond.iLastUsed)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TInt RenderBufferTimeOrderFunc(const CHuiCanvasRenderBufferImage& aFirst, const CHuiCanvasRenderBufferImage& aSecond)
+ {
+ if (aFirst.iLastUsed < aSecond.iLastUsed)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iLastUsed > aSecond.iLastUsed)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TInt GcImageOrderFunc(const THuiCachedGcParams& /*aFirst*/, const THuiCachedGcParams& /*aSecond*/)
+ {
+ return 0; // equal enough, note that we don't check every field
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TInt GcTextOrderFunc(const THuiCachedGcParams& aFirst, const THuiCachedGcParams& aSecond)
+ {
+ if (!KHuiCanvasTextUseColorModulation)
+ {
+ if (aFirst.iPenColor.Value() < aSecond.iPenColor.Value())
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iPenColor.Value() > aSecond.iPenColor.Value())
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+ }
+
+ if (aFirst.iPenStyle < aSecond.iPenStyle)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iPenStyle > aSecond.iPenStyle)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ if (aFirst.iDrawMode < aSecond.iDrawMode)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iDrawMode > aSecond.iDrawMode)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ if (aFirst.iStrikethrough < aSecond.iStrikethrough)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iStrikethrough > aSecond.iStrikethrough)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ if (aFirst.iUnderline < aSecond.iUnderline)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iUnderline > aSecond.iUnderline)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ return 0; // equal enough, note that we don't check every field
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TInt ImageOrderFunc(const CHuiCanvasGraphicImage& aFirst, const CHuiCanvasGraphicImage& aSecond)
+ {
+ // Bitmap handle
+ if (aFirst.iBitmapHandle < aSecond.iBitmapHandle)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iBitmapHandle > aSecond.iBitmapHandle)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ // Mask handle
+ if (aFirst.iMaskHandle < aSecond.iMaskHandle)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iMaskHandle > aSecond.iMaskHandle)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ // Inverted mask
+ if (aFirst.iInvertedMask < aSecond.iInvertedMask)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iInvertedMask > aSecond.iInvertedMask)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ // Mask origin point X
+ if (aFirst.iMaskOriginPoint.iX < aSecond.iMaskOriginPoint.iX)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iMaskOriginPoint.iX > aSecond.iMaskOriginPoint.iX)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ // Mask origin point Y
+ if (aFirst.iMaskOriginPoint.iY < aSecond.iMaskOriginPoint.iY)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iMaskOriginPoint.iY > aSecond.iMaskOriginPoint.iY)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ if (aFirst.iImageSize.iHeight < aSecond.iImageSize.iHeight)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iImageSize.iHeight > aSecond.iImageSize.iHeight)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ if (aFirst.iImageSize.iWidth < aSecond.iImageSize.iWidth)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iImageSize.iWidth > aSecond.iImageSize.iWidth)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ if (aFirst.iSubImages.Count() < aSecond.iSubImages.Count())
+ {
+ return -1;
+ }
+ else if (aFirst.iSubImages.Count() > aSecond.iSubImages.Count())
+ {
+ return 1;
+ }
+ else
+ {
+ // Same amount, must check array content
+ if (aFirst.iSubImages.Count() && aSecond.iSubImages.Count())
+ {
+ for (TInt i=0; i<aFirst.iSubImages.Count();i++)
+ {
+ if (aFirst.iSubImages[i].iBitmapHandle < aSecond.iSubImages[i].iBitmapHandle)
+ {
+ return -1;
+ }
+ else if (aFirst.iSubImages[i].iBitmapHandle > aSecond.iSubImages[i].iBitmapHandle)
+ {
+ return 1;
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ if (aFirst.iSubImages[i].iMaskHandle < aSecond.iSubImages[i].iMaskHandle)
+ {
+ return -1;
+ }
+ else if (aFirst.iSubImages[i].iMaskHandle > aSecond.iSubImages[i].iMaskHandle)
+ {
+ return 1;
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ if (aFirst.iSubImages[i].iCombinedBitmapPoint.iX < aSecond.iSubImages[i].iCombinedBitmapPoint.iX)
+ {
+ return -1;
+ }
+ else if (aFirst.iSubImages[i].iCombinedBitmapPoint.iX > aSecond.iSubImages[i].iCombinedBitmapPoint.iX)
+ {
+ return 1;
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ if (aFirst.iSubImages[i].iCombinedBitmapPoint.iY < aSecond.iSubImages[i].iCombinedBitmapPoint.iY)
+ {
+ return -1;
+ }
+ else if (aFirst.iSubImages[i].iCombinedBitmapPoint.iY > aSecond.iSubImages[i].iCombinedBitmapPoint.iY)
+ {
+ return 1;
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+
+ }
+ }
+ else
+ {
+ // For PC-lint
+ }
+ }
+ return GcImageOrderFunc(aFirst.iGcParams, aSecond.iGcParams);
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TInt TextOrderFunc(const CHuiCanvasTextImage& aFirst, const CHuiCanvasTextImage& aSecond)
+ {
+ // Font handle
+ if (aFirst.iFontHandle < aSecond.iFontHandle)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iFontHandle > aSecond.iFontHandle)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ // Text width
+ if (aFirst.iTextWidth < aSecond.iTextWidth)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iTextWidth > aSecond.iTextWidth)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ // iTextBoxMaxSize.iWidth
+ if (aFirst.iTextBoxMaxSize.iWidth < aSecond.iTextBoxMaxSize.iWidth)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iTextBoxMaxSize.iWidth > aSecond.iTextBoxMaxSize.iWidth)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ // Text content
+ TInt textcompare = KErrNotFound;
+ if ( aFirst.iFindTextPtr )
+ {
+ textcompare = aFirst.iFindTextPtr->Compare(*aSecond.iText);
+ }
+ else
+ {
+ textcompare = aFirst.iText->Compare(*aSecond.iText);
+ }
+
+ if (textcompare < 0)
+ {
+ return -1;
+ }
+ else if (textcompare > 0)
+ {
+ return 1;
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ // iBaseLineOffset
+ if (aFirst.iBaseLineOffset < aSecond.iBaseLineOffset)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iBaseLineOffset > aSecond.iBaseLineOffset)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ // iTextAlign
+ if (aFirst.iTextAlign < aSecond.iTextAlign)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iTextAlign > aSecond.iTextAlign)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ // iMargin
+ if (aFirst.iMargin < aSecond.iMargin)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iMargin > aSecond.iMargin)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ // iAngle
+ if (aFirst.iAngle < aSecond.iAngle)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iAngle > aSecond.iAngle)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ // Font handle
+ if (aFirst.iTextParams.iStart < aSecond.iTextParams.iStart)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iTextParams.iStart > aSecond.iTextParams.iStart)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ // Font handle
+ if (aFirst.iTextParams.iEnd < aSecond.iTextParams.iEnd)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iTextParams.iEnd > aSecond.iTextParams.iEnd)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ // Font handle
+ if (aFirst.iTextParams.iFlags < aSecond.iTextParams.iFlags)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iTextParams.iFlags > aSecond.iTextParams.iFlags)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ return GcTextOrderFunc(aFirst.iGcParams, aSecond.iGcParams);
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TInt RenderBufferOrderFunc(const CHuiCanvasRenderBufferImage& aFirst, const CHuiCanvasRenderBufferImage& aSecond)
+ {
+ if (aFirst.iOwner < aSecond.iOwner)
+ {
+ return -1; // less than
+ }
+ else if (aFirst.iOwner > aSecond.iOwner)
+ {
+ return 1; // more than
+ }
+ else
+ {
+ // For PC-lint
+ }
+
+ return 0; // Equal
+ }
+
+
+// ---------------------------------------------------------------------------
+// Constructor
+// ---------------------------------------------------------------------------
+//
+CHuiCanvasTextureCache::CHuiCanvasTextureCache()
+ {
+ EnableLowMemoryState(EFalse);
+ CHuiStatic::Env().AddLowMemoryObserver(this);
+ }
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CHuiCanvasTextureCache::~CHuiCanvasTextureCache()
+ {
+ CHuiStatic::Env().RemoveLowMemoryObserver(this);
+ iCachedTexts.ResetAndDestroy();
+ iCachedImages.ResetAndDestroy();
+ iRecycledTextures.ResetAndDestroy();
+
+ if (iSearchedTextImageEntry)
+ {
+ iSearchedTextImageEntry->Reset();
+ delete iSearchedTextImageEntry;
+ }
+
+ if (iSearchedGraphicImageEntry)
+ {
+ iSearchedGraphicImageEntry->Reset();
+ delete iSearchedGraphicImageEntry;
+ }
+
+ if (iSearchedRenderBufferImageEntry)
+ {
+ iSearchedRenderBufferImageEntry->Reset();
+ delete iSearchedRenderBufferImageEntry;
+ }
+
+ delete iTextImageRasterizer;
+ delete iOutLineTextImageRasterizer;
+ delete iGraphicImageRasterizer;
+ delete iCombinedGraphicImageRasterizer;
+ delete iCanvasGc;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+CHuiCanvasTextureCache* CHuiCanvasTextureCache::NewL()
+ {
+ CHuiCanvasTextureCache* self = CHuiCanvasTextureCache::NewLC();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+CHuiCanvasTextureCache* CHuiCanvasTextureCache::NewLC()
+ {
+ CHuiCanvasTextureCache* self = new (ELeave) CHuiCanvasTextureCache();
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CHuiCanvasTextureCache::ConstructL()
+ {
+ iMemoryLevel = EHuiMemoryLevelNormal;
+
+ iCanvasGc = CHuiStatic::Renderer().CreateCanvasGcL();
+
+ iTextImageRasterizer = new (ELeave) CHuiCanvasTextImageRasterizer;
+ iTextImageRasterizer->ConstructL(EGray256);
+
+ iOutLineTextImageRasterizer = new (ELeave) CHuiCanvasTextImageRasterizer;
+ iOutLineTextImageRasterizer->ConstructL(EColor16MA);
+
+ iGraphicImageRasterizer = new (ELeave) CHuiCanvasGraphicImageRasterizer;
+ iGraphicImageRasterizer->ConstructL();
+
+ iCombinedGraphicImageRasterizer = new (ELeave) CHuiCanvasCombinedGraphicImageRasterizer;
+ iCombinedGraphicImageRasterizer->ConstructL(EColor64K);
+
+ iSearchedTextImageEntry = new (ELeave) CHuiCanvasTextImage;
+ iSearchedGraphicImageEntry = new (ELeave) CHuiCanvasGraphicImage;
+ iSearchedRenderBufferImageEntry = new (ELeave) CHuiCanvasRenderBufferImage;
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+//
+// ---------------------------------------------------------------------------
+//
+const CHuiCanvasGraphicImage* CHuiCanvasTextureCache::FindCachedImageL(
+ const THuiCachedImageParams& aCachedImageParams,
+ const CHuiCanvasVisual& aUser)
+ {
+ TInt cachedEntry = KErrNotFound;
+
+ iSearchedGraphicImageEntry->Reset();
+ iSearchedGraphicImageEntry->iBitmapHandle = aCachedImageParams.iBitmapHandle;
+ iSearchedGraphicImageEntry->iMaskHandle = aCachedImageParams.iMaskHandle;
+ iSearchedGraphicImageEntry->iTexture = NULL;
+ iSearchedGraphicImageEntry->iInvertedMask = aCachedImageParams.iInvertedMask;
+ iSearchedGraphicImageEntry->iMaskOriginPoint = aCachedImageParams.iMaskOriginPoint;
+ iSearchedGraphicImageEntry->iBitmapTouchCount = KHuiInitialBitmapTouchCount;
+ iSearchedGraphicImageEntry->iMaskTouchCount = KHuiInitialBitmapTouchCount;
+ iSearchedGraphicImageEntry->iGcParams = aCachedImageParams.iGcParams;
+
+ cachedEntry = iCachedImages.FindInOrder(iSearchedGraphicImageEntry, ImageOrderFunc);
+ if (cachedEntry == KErrNotFound)
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ iCachedImages[cachedEntry]->RefreshUser(aUser);
+ return iCachedImages[cachedEntry];
+ }
+
+// ---------------------------------------------------------------------------
+//
+//
+// ---------------------------------------------------------------------------
+//
+const CHuiCanvasGraphicImage* CHuiCanvasTextureCache::CreateCombinedCachedImageL(
+ const RArray<THuiCachedCombinedImageParams>& aCachedImageParams,
+ const THuiCachedGcParams& aGcParams,
+ const TSize& aImageSize,
+ const CHuiCanvasVisual& aUser)
+ {
+ TBool needUpdate = EFalse;
+ TInt cachedEntry = KErrNotFound;
+
+ iSearchedGraphicImageEntry->Reset();
+ iSearchedGraphicImageEntry->iGcParams = aGcParams;
+ iSearchedGraphicImageEntry->iImageSize = aImageSize;
+
+
+ for (TInt i=0; i<aCachedImageParams.Count();i++)
+ {
+ THuiCachedBitmap cachedBitmap;
+ cachedBitmap.iBitmapHandle = aCachedImageParams[i].iBitmapHandle;
+ cachedBitmap.iMaskHandle = aCachedImageParams[i].iMaskHandle;
+ cachedBitmap.iCombinedBitmapPoint = aCachedImageParams[i].iCombinedBitmapPoint;
+ iSearchedGraphicImageEntry->iSubImages.Append(cachedBitmap);
+ }
+
+ cachedEntry = iCachedImages.FindInOrder(iSearchedGraphicImageEntry, ImageOrderFunc);
+ if (cachedEntry == KErrNotFound)
+ {
+ // Create new entry object
+ CHuiCanvasGraphicImage* newEntry = new (ELeave) CHuiCanvasGraphicImage;
+ CleanupStack::PushL(newEntry);
+ newEntry->CopyAttributes(*iSearchedGraphicImageEntry);
+
+ // Create new accelerated image
+ CHuiTexture* newtexture = CreateRecycledTextureL();
+ newEntry->iTexture = newtexture;
+
+ User::LeaveIfError(iCachedImages.InsertInOrder(newEntry, ImageOrderFunc));
+ cachedEntry = iCachedImages.FindInOrder(newEntry, ImageOrderFunc);
+
+ CleanupStack::Pop(newEntry);
+ needUpdate = ETrue;
+ }
+ else
+ {
+ // Check if needs to be updated by checking active users list
+ if (!iCachedImages[cachedEntry]->IsUser(aUser))
+ {
+ needUpdate = ETrue;
+ }
+ }
+
+ if (needUpdate)
+ {
+ TRAPD(updateError, iCombinedGraphicImageRasterizer->RasterizeL(*iCachedImages[cachedEntry]));
+ if (updateError == KErrNoMemory)
+ {
+ // Call grim reaper to initiate system level texture memory actions !
+ HandleOutOfTextureMemory();
+ User::LeaveIfError(updateError);
+ }
+ }
+
+ iCachedImages[cachedEntry]->RefreshUser(aUser);
+ return iCachedImages[cachedEntry];
+ }
+
+
+// ---------------------------------------------------------------------------
+// Improvement idea for HW accelerated, upload all images of the buffer
+// into single texture and use texture coordinates to draw each image.
+// ---------------------------------------------------------------------------
+//
+const CHuiCanvasGraphicImage* CHuiCanvasTextureCache::CreateCachedImageL(
+ const THuiCachedImageParams& aCachedImageParams,
+ const CHuiCanvasVisual& aUser)
+ {
+ TBool needUpdate = EFalse;
+ TInt cachedEntry = KErrNotFound;
+
+ iSearchedGraphicImageEntry->Reset();
+ iSearchedGraphicImageEntry->iBitmapHandle = aCachedImageParams.iBitmapHandle;
+ iSearchedGraphicImageEntry->iMaskHandle = aCachedImageParams.iMaskHandle;
+ iSearchedGraphicImageEntry->iTexture = NULL;
+ iSearchedGraphicImageEntry->iInvertedMask = aCachedImageParams.iInvertedMask;
+ iSearchedGraphicImageEntry->iMaskOriginPoint = aCachedImageParams.iMaskOriginPoint;
+ iSearchedGraphicImageEntry->iBitmapTouchCount = KHuiInitialBitmapTouchCount;
+ iSearchedGraphicImageEntry->iMaskTouchCount = KHuiInitialBitmapTouchCount;
+ iSearchedGraphicImageEntry->iGcParams = aCachedImageParams.iGcParams;
+
+ cachedEntry = iCachedImages.FindInOrder(iSearchedGraphicImageEntry, ImageOrderFunc);
+ if (cachedEntry == KErrNotFound)
+ {
+ // Create new entry object
+ CHuiCanvasGraphicImage* newEntry = new (ELeave) CHuiCanvasGraphicImage;
+ CleanupStack::PushL(newEntry);
+
+ newEntry->CopyAttributes(*iSearchedGraphicImageEntry);
+
+ // Create new accelerated image
+ CHuiTexture* newtexture = CreateRecycledTextureL();
+ newEntry->iTexture = newtexture;
+
+ User::LeaveIfError(iCachedImages.InsertInOrder(newEntry, ImageOrderFunc));
+ cachedEntry = iCachedImages.FindInOrder(newEntry, ImageOrderFunc);
+ CleanupStack::Pop(newEntry);
+ needUpdate = ETrue;
+ }
+ else
+ {
+ // Check if needs to be updated by checking active users list
+ if (!iCachedImages[cachedEntry]->IsUser(aUser))
+ {
+ needUpdate = ETrue;
+ }
+ }
+
+ if (needUpdate)
+ {
+ TRAPD(updateError, iGraphicImageRasterizer->RasterizeL(*iCachedImages[cachedEntry]));
+ if (updateError == KErrNoMemory)
+ {
+ // Call grim reaper to initiate system level texture memory actions !
+ HandleOutOfTextureMemory();
+ User::LeaveIfError(updateError);
+ }
+ }
+
+ iCachedImages[cachedEntry]->RefreshUser(aUser);
+ return iCachedImages[cachedEntry];
+ }
+
+
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+const CHuiCanvasTextImage* CHuiCanvasTextureCache::CreateCachedTextL(
+ const THuiCachedTextParams& aCachedTextParams,
+ const CHuiCanvasVisual& aUser)
+ {
+ TBool needUpdate = EFalse;
+ TInt cachedEntry = KErrNotFound;
+
+ iSearchedTextImageEntry->Reset();
+ iSearchedTextImageEntry->iFindTextPtr= aCachedTextParams.iFindTextPtr; // Not owned, gets be updated if not found
+ iSearchedTextImageEntry->iTexture = NULL; // Gets updated if not found
+ iSearchedTextImageEntry->iFontHandle = aCachedTextParams.iFontHandle;
+ iSearchedTextImageEntry->iRasterizationOffset = TPoint(0,0); // Gets updated when text has been rasterized
+ Mem::Copy( &iSearchedTextImageEntry->iTextParams, &aCachedTextParams.iTextParams, sizeof(THuiCanvasTextParameters));
+ iSearchedTextImageEntry->iTextBoxMaxSize = aCachedTextParams.iTextBoxMaxSize;
+ iSearchedTextImageEntry->iTextWidth = aCachedTextParams.iTextWidth;
+ iSearchedTextImageEntry->iBaseLineOffset = aCachedTextParams.iBaseLineOffset;
+ iSearchedTextImageEntry->iTextAlign = aCachedTextParams.iTextAlign;
+ iSearchedTextImageEntry->iMargin = aCachedTextParams.iMargin;
+ iSearchedTextImageEntry->iAngle = aCachedTextParams.iAngle;
+ iSearchedTextImageEntry->iGcParams = aCachedTextParams.iGcParams;
+
+
+ cachedEntry = iCachedTexts.FindInOrder(iSearchedTextImageEntry, TextOrderFunc);
+ if (cachedEntry == KErrNotFound)
+ {
+ // Create new entry object
+ CHuiCanvasTextImage* newTextEntry = new (ELeave) CHuiCanvasTextImage;
+ CleanupStack::PushL(newTextEntry);
+
+ newTextEntry->CopyAttributes(*iSearchedTextImageEntry);
+
+ // Create new accelerated image
+ CHuiTexture* newtexture = CreateRecycledTextureL();
+ newTextEntry->iTexture = newtexture;
+
+ // Create text which entry will own
+ HBufC* ownedText = aCachedTextParams.iFindTextPtr->AllocL();
+ newTextEntry->iText = ownedText;
+ newTextEntry->iFindTextPtr = NULL;
+ TInt insertSuccess = iCachedTexts.InsertInOrder(newTextEntry, TextOrderFunc);
+ __ASSERT_DEBUG( !insertSuccess, USER_INVARIANT() );
+ User::LeaveIfError( insertSuccess );
+ cachedEntry = iCachedTexts.FindInOrder(newTextEntry, TextOrderFunc);
+
+ CleanupStack::Pop(newTextEntry);
+ needUpdate = ETrue;
+ }
+ else
+ {
+ // If it was found, great. No need to update it.
+ }
+
+
+ if (needUpdate)
+ {
+ TBool outlinefont = EFalse;
+
+ if (!(*iCachedTexts[cachedEntry]).iFont)
+ {
+ CFbsBitGcFont* font = new (ELeave) CFbsBitGcFont();
+ CleanupStack::PushL(font);
+ User::LeaveIfError(font->Duplicate((*iCachedTexts[cachedEntry]).iFontHandle));
+ (*iCachedTexts[cachedEntry]).iFont = font;
+ CleanupStack::Pop(); // font
+ }
+
+ outlinefont = (*iCachedTexts[cachedEntry]).iFont->FontSpecInTwips().iFontStyle.IsEffectOn(FontEffect::EOutline);
+ TInt updateError(KErrNone);
+ if (!outlinefont)
+ {
+ TRAP(updateError, iTextImageRasterizer->RasterizeL(*iCachedTexts[cachedEntry]));
+ }
+ else
+ {
+ TRAP(updateError, iOutLineTextImageRasterizer->RasterizeL(*iCachedTexts[cachedEntry]));
+ }
+
+
+
+ if (updateError == KErrNoMemory)
+ {
+ // Call grim reaper to initiate system level texture memory actions !
+ HandleOutOfTextureMemory();
+ User::LeaveIfError(updateError);
+ }
+ }
+
+ iCachedTexts[cachedEntry]->RefreshUser(aUser);
+ return iCachedTexts[cachedEntry];
+ }
+
+
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CHuiCanvasTextureCache::ReleaseAllCachedEntries(const CHuiCanvasVisual& aUser)
+ {
+ // Texts
+ for (TInt i=0; i < iCachedTexts.Count(); i++)
+ {
+ TInt index = iCachedTexts[i]->iActiveUsers.FindInAddressOrder(&aUser);
+
+ if (index != KErrNotFound)
+ {
+ iCachedTexts[i]->iActiveUsers.Remove(index);
+ iHasReleasedTexts = ETrue;
+ }
+ }
+
+ // Images
+ for (TInt i=0; i < iCachedImages.Count(); i++)
+ {
+ TInt index = iCachedImages[i]->iActiveUsers.FindInAddressOrder(&aUser);
+
+ if (index != KErrNotFound)
+ {
+ iCachedImages[i]->iActiveUsers.Remove(index);
+ iHasReleasedImages = ETrue;
+ }
+ }
+
+ // Render buffers are _not_ released together with images and text
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CHuiCanvasTextureCache::DeleteAllReleasedEntries(TBool aAllowKeepCached)
+ {
+ // Texts
+ if (iHasReleasedTexts)
+ {
+ RPointerArray<CHuiCanvasTextImage> unusedEntries;
+
+ FindUnusedTextEntries(unusedEntries);
+
+ // Remove unused entries if they fit into the cache, leave last used ones in the cache if cache size allows
+ if (aAllowKeepCached)
+ {
+ SelectPreservedUnusedTextEntries(unusedEntries);
+ }
+
+ DeleteUnusedTextEntries(unusedEntries);
+
+ unusedEntries.Close();
+ iHasReleasedTexts = EFalse;
+ }
+
+ // Images
+ if (iHasReleasedImages)
+ {
+ RPointerArray<CHuiCanvasGraphicImage> unusedEntries;
+
+ FindUnusedImageEntries(unusedEntries);
+
+ // Remove unused entries if they fit into the cache, leave last used ones in the cache if cache size allows
+ if (aAllowKeepCached)
+ {
+ SelectPreservedUnusedImageEntries(unusedEntries);
+ }
+
+ DeleteUnusedImageEntries(unusedEntries);
+
+ unusedEntries.Close();
+ iHasReleasedImages = EFalse;
+ }
+
+ // Render buffers
+ if (iHasReleasedRenderBuffers)
+ {
+ RPointerArray<CHuiCanvasRenderBufferImage> unusedEntries;
+
+ FindUnusedRenderBufferEntries(unusedEntries);
+
+ // Remove unused entries if they fit into the cache, leave last used ones in the cache if cache size allows
+ if (aAllowKeepCached)
+ {
+ SelectPreservedUnusedRenderBufferEntries(unusedEntries);
+ }
+
+ DeleteUnusedRenderBufferEntries(unusedEntries);
+
+ unusedEntries.Close();
+ iHasReleasedRenderBuffers = EFalse;
+ }
+ }
+
+#ifdef HUI_DEBUG_PRINT_CANVAS_TEXTURE_CACHE_EGL
+#include "eglext.h"
+typedef EGLBoolean (*NOK_resource_profiling)(EGLDisplay, EGLint, EGLint*, EGLint, EGLint*);
+
+void ReportGraphicsMemoryUsage()
+ {
+ RDebug::Print(_L("About to ask EGL profiling ext"));
+ EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+ /*
+ ** Search for extName in the extensions string. Use of strstr()
+ ** is not sufficient because extension names can be prefixes of
+ ** other extension names. Could use strtok() but the constant
+ ** string returned by glGetString can be in read-only memory.
+ */
+ /* TBool extensionFound = EFalse;
+ char *p = (char *) eglQueryString(dpy,EGL_EXTENSIONS);
+ char *end;
+ int extNameLen = strlen("EGL_NOK_resource_profiling");
+ end = p + strlen(p);
+
+ while (p < end)
+ {
+ int n = strcspn(p, " ");
+ if ((extNameLen == n) && (strncmp("EGL_NOK_resource_profiling", p, n) == 0))
+ {
+ extensionFound = ETrue;
+ break;
+ }
+ p += (n + 1);
+ }
+
+ if (!extensionFound)
+ {
+ TRACES("EGL_NOK_resource_profiling not found from EGL_EXTENSIONS");
+ }*/
+ // okay, let's fetch the function ptr to our profiling functions
+ // resource profiling extension function ptr
+ NOK_resource_profiling eglQueryProfilingData = (NOK_resource_profiling)eglGetProcAddress("eglQueryProfilingDataNOK");
+ if (!eglQueryProfilingData)
+ {
+ RDebug::Print(_L("EGL profiling ext not present"));
+ return;
+ }
+
+ EGLint data_count;
+ EGLint* prof_data;
+ TInt i(0);
+
+ /* Find out how much profiling data is available */
+ eglQueryProfilingData(dpy, EGL_PROF_QUERY_GLOBAL_BIT_NOK | EGL_PROF_QUERY_MEMORY_USAGE_BIT_NOK,
+ NULL, 0, &data_count);
+
+ /* Allocate room for the profiling data */
+ prof_data = (EGLint*)User::Alloc(data_count * sizeof(EGLint));
+ if (prof_data == NULL)
+ {
+ RDebug::Print(_L("Could not get mem for EGL profiling ext"));
+ return;
+ }
+ /* Retrieve the profiling data */
+ eglQueryProfilingData(dpy,
+ EGL_PROF_QUERY_GLOBAL_BIT_NOK |
+ EGL_PROF_QUERY_MEMORY_USAGE_BIT_NOK,
+ prof_data,
+ data_count,
+ &data_count);
+
+ /* Iterate over the returned data */
+ while (i < data_count)
+ {
+ switch (prof_data[i++])
+ {
+ case EGL_PROF_USED_MEMORY_NOK:
+ {
+ RDebug::Print(_L("EGL Profiling: used mem %d"), prof_data[i++]);
+ break;
+ }
+ case EGL_PROF_TOTAL_MEMORY_NOK:
+ {
+ RDebug::Print(_L("EGL Profiling: total mem available: %d"), prof_data[i++]);
+ break;
+ }
+ case EGL_PROF_THREAD_ID_NOK:
+ {
+ if (sizeof(EGLNativeThreadIdTypeNOK) == 8)
+ {
+ i+=2;
+ }
+ else
+ {
+ i++;
+ }
+ break;
+ }
+ case EGL_PROF_THREAD_USED_PRIVATE_MEMORY_NOK:
+ case EGL_PROF_THREAD_USED_SHARED_MEMORY_NOK:
+ default:
+ {
+ i++;
+ break;
+ }
+ }
+ }
+
+ User::Free(prof_data);
+ }
+
+#endif
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CHuiCanvasTextureCache::AdvanceTime()
+ {
+#ifdef HUI_DEBUG_PRINT_CANVAS_TEXTURE_CACHE
+ RDebug::Print(_L("-- CHuiCanvasTextureCache::AdvanceTime: begin --"));
+ if (IsLowMemoryStateEnabled())
+ {
+ RDebug::Print(_L("-- CHuiCanvasTextureCache::AdvanceTime: LOW MEMORY STATE ENABLED"));
+ }
+ if(iEglProfiling > 10)
+ {
+#ifdef HUI_DEBUG_PRINT_CANVAS_TEXTURE_CACHE_EGL
+ ReportGraphicsMemoryUsage();
+#endif
+ iEglProfiling = 0;
+ }
+ else
+ {
+ iEglProfiling++;
+ }
+#endif
+
+ // We do not delete all, by leaving something unused in the cache
+ // we can improve performance.
+ CalculateGraphicsMemoryUsage();
+ DeleteAllReleasedEntries(ETrue);
+
+ // Reset bitmap sizes to save memory. Commented out as resize appears to
+ // be relatively slow (0.2 - 0.5 ms). Not resizing here means that it uses
+ // more RAM between frames.
+ //iTempMask->Resize(KEmptyBitmapSize);
+ //iTempBitmap->Resize(KEmptyBitmapSize);
+
+ //iFontHandle = 0;
+ //delete iFont;
+ //iFont = NULL;
+
+#ifdef HUI_DEBUG_PRINT_CANVAS_TEXTURE_CACHE
+ RDebug::Print(_L("-- Cached texts: %i --"), iCachedTexts.Count());
+ RDebug::Print(_L("-- Cached imgs : %i --"), iCachedImages.Count());
+
+ TInt totalPixels = 0;
+
+ for(TInt i=iCachedTexts.Count() - 1; i >= 0; i--)
+ {
+ TSize size = iCachedTexts[i]->iTexture->Size();
+ RDebug::Print(_L("-- Cached text: %ix%i, users=%i, string=%S --"), size.iWidth, size.iHeight, iCachedTexts[i]->iActiveUsers.Count(), iCachedTexts[i]->iText );
+ totalPixels += size.iWidth * size.iHeight;
+
+#ifdef HUI_DEBUG_PRINT_CANVAS_TEXTURE_CACHE_EXTENDED
+
+ RDebug::Print(_L("-- iFontHandle: %i --"), iCachedTexts[i]->iFontHandle );
+ RDebug::Print(_L("-- iTextWidth: %i --"), iCachedTexts[i]->iTextWidth );
+ RDebug::Print(_L("-- iTextBoxMaxSize.iWidth: %i --"), iCachedTexts[i]->iTextBoxMaxSize.iWidth );
+ RDebug::Print(_L("-- iBaseLineOffset: %i --"), iCachedTexts[i]->iBaseLineOffset );
+ RDebug::Print(_L("-- iTextAlign: %i --"), iCachedTexts[i]->iTextAlign );
+ RDebug::Print(_L("-- iMargin: %i --"), iCachedTexts[i]->iMargin );
+ RDebug::Print(_L("-- iAngle: %i --"), iCachedTexts[i]->iAngle );
+ RDebug::Print(_L("-- iTextParams.iStart: %i --"), iCachedTexts[i]->iTextParams.iStart );
+ RDebug::Print(_L("-- iTextParams.iEnd: %i --"), iCachedTexts[i]->iTextParams.iEnd );
+ RDebug::Print(_L("-- iTextParams.iFlagst: %i --"), iCachedTexts[i]->iTextParams.iFlags );
+
+
+ THuiCachedGcParams p = iCachedTexts[i]->iGcParams;
+ RDebug::Print(_L("-- iPenColor: %i --"), p.iPenColor );
+ RDebug::Print(_L("-- iPenStyle: %i --"), p.iPenStyle );
+ RDebug::Print(_L("-- iDrawMode: %i --"), p.iDrawMode );
+ RDebug::Print(_L("-- iBrushColor: %i --"), p.iBrushColor );
+ RDebug::Print(_L("-- iBrushStyle: %i --"), p.iBrushStyle );
+ RDebug::Print(_L("-- iShadowMode: %i --"), p.iShadowMode );
+ RDebug::Print(_L("-- iStrikethrough: %i --"), p.iStrikethrough );
+ RDebug::Print(_L("-- iUnderline: %i --"), p.iUnderline );
+ RDebug::Print(_L("-- iUserDisplayMode: %i --"), p.iUserDisplayMode );
+ RDebug::Print(_L("-- iShadowColor: %i --"), p.iShadowColor );
+#endif
+ }
+
+ for(TInt i=iCachedImages.Count() - 1; i >= 0; i--)
+ {
+ TSize size = iCachedImages[i]->iTexture->Size();
+ if (iCachedImages[i]->iSubImages.Count())
+ {
+ RDebug::Print(_L("-- Cached combined image: %i+%i %ix%i, users=%i --"), iCachedImages[i]->iBitmapHandle, iCachedImages[i]->iMaskHandle, size.iWidth, size.iHeight, iCachedImages[i]->iActiveUsers.Count());
+ RDebug::Print(_L("-- Blit size: %ix%i --"), iCachedImages[i]->iImageSize.iWidth, iCachedImages[i]->iImageSize.iHeight);
+ for (TInt j=0; j<iCachedImages[i]->iSubImages.Count();j++)
+ {
+ RDebug::Print(_L("-- subimage: %i+%i Point: %i,%i--"),
+ iCachedImages[i]->iSubImages[j].iBitmapHandle,
+ iCachedImages[i]->iSubImages[j].iMaskHandle,
+ iCachedImages[i]->iSubImages[j].iCombinedBitmapPoint.iX,
+ iCachedImages[i]->iSubImages[j].iCombinedBitmapPoint.iY);
+ }
+ }
+ else
+ {
+ RDebug::Print(_L("-- Cached image: %i+%i %ix%i, users=%i --"), iCachedImages[i]->iBitmapHandle,iCachedImages[i]->iMaskHandle, size.iWidth, size.iHeight, iCachedImages[i]->iActiveUsers.Count());
+ }
+
+ totalPixels += size.iWidth * size.iHeight;
+ }
+
+ RDebug::Print(_L("-- Estimated canvas texture mem usage with 32bpp %i KBytes --"), totalPixels*4 / 1024);
+
+ TInt unusedCanvasTextures = CalculateUnusedCanvasTextureUsageInKbytes();
+
+ RDebug::Print(_L("-- Estimated canvas unused texture mem usage with 32bpp %i KBytes --"), unusedCanvasTextures);
+
+ TInt totalUsedTextureMemoryInKBytes = CHuiStatic::Env().TextureManager().EstimatedTextureMemUsage(KHuiTextureEstimatedBpp) / 1024;
+
+ RDebug::Print(_L("-- Estimated total texture mem usage with 32bpp %i KBytes --"), totalUsedTextureMemoryInKBytes);
+
+ TInt totalPixelsForRenderBuffers = 0;
+ for(TInt i=iCachedRenderBuffers.Count() - 1; i >= 0; i--)
+ {
+ if (iCachedRenderBuffers[i]->iCanvasRenderBuffer)
+ {
+ TSize size = iCachedRenderBuffers[i]->iCanvasRenderBuffer->Size();
+ RDebug::Print(_L("-- Cached render buffer: %ix%i, users=%i --"), size.iWidth, size.iHeight, iCachedRenderBuffers[i]->iActiveUsers.Count());
+ totalPixelsForRenderBuffers += size.iWidth * size.iHeight;
+ }
+ else
+ {
+ RDebug::Print(_L("-- Cached render buffer: 0x0, users=%i --"), iCachedRenderBuffers[i]->iActiveUsers.Count());
+ }
+ }
+ RDebug::Print(_L("-- Estimated canvas render buffer mem usage with 32bpp %i KBytes --"), totalPixelsForRenderBuffers*4 / 1024);
+
+ TInt totalAllocSize = 0;
+ User::AllocSize(totalAllocSize);
+ RDebug::Print(_L("-- User::AllocSize = %i"), totalAllocSize);
+
+ RDebug::Print(_L("-- CHuiCanvasTextureCache::AdvanceTime: end --"));
+#endif
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CHuiCanvasTextureCache::FindUnusedImageEntries(RPointerArray<CHuiCanvasGraphicImage>& aIndexEntries)
+ {
+ for(TInt i=iCachedImages.Count() - 1; i >= 0; i--)
+ {
+ CHuiCanvasGraphicImage* entry = iCachedImages[i];
+ if (!entry->iActiveUsers.Count())
+ {
+ aIndexEntries.InsertInOrderAllowRepeats(entry, ImageTimeOrderFunc);
+ }
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CHuiCanvasTextureCache::FindUnusedTextEntries(RPointerArray<CHuiCanvasTextImage>& aIndexEntries)
+ {
+ for(TInt i=iCachedTexts.Count() - 1; i >= 0; i--)
+ {
+ CHuiCanvasTextImage* entry = iCachedTexts[i];
+
+ if (!entry->iActiveUsers.Count())
+ {
+ aIndexEntries.InsertInOrderAllowRepeats(entry, TextTimeOrderFunc);
+ }
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CHuiCanvasTextureCache::FindUnusedRenderBufferEntries(RPointerArray<CHuiCanvasRenderBufferImage>& aIndexEntries)
+ {
+ for(TInt i=iCachedRenderBuffers.Count() - 1; i >= 0; i--)
+ {
+ CHuiCanvasRenderBufferImage* entry = iCachedRenderBuffers[i];
+
+ if (!entry->iActiveUsers.Count())
+ {
+ aIndexEntries.InsertInOrderAllowRepeats(entry, RenderBufferTimeOrderFunc);
+ }
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CHuiCanvasTextureCache::DeleteUnusedImageEntries(RPointerArray<CHuiCanvasGraphicImage>& aIndexEntries)
+ {
+ // Remove given entries
+ for(TInt i=aIndexEntries.Count() - 1; i >= 0; i--)
+ {
+ TInt indexEntry = iCachedImages.FindInOrder(aIndexEntries[i], ImageOrderFunc);
+ if (indexEntry != KErrNotFound)
+ {
+ CHuiCanvasGraphicImage* entry = iCachedImages[indexEntry];
+ iCachedImages.Remove(indexEntry);
+ delete entry;
+ }
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CHuiCanvasTextureCache::DeleteUnusedTextEntries(RPointerArray<CHuiCanvasTextImage>& aIndexEntries)
+ {
+ // Remove given entries
+ for(TInt i=aIndexEntries.Count() - 1; i >= 0; i--)
+ {
+ TInt indexEntry = iCachedTexts.FindInOrder(aIndexEntries[i], TextOrderFunc);
+ if (indexEntry != KErrNotFound)
+ {
+ CHuiCanvasTextImage* entry = iCachedTexts[indexEntry];
+ iCachedTexts.Remove(indexEntry);
+ delete entry;
+ }
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CHuiCanvasTextureCache::DeleteUnusedRenderBufferEntries(RPointerArray<CHuiCanvasRenderBufferImage>& aIndexEntries)
+ {
+ // Remove given entries
+ for(TInt i=aIndexEntries.Count() - 1; i >= 0; i--)
+ {
+ TInt indexEntry = iCachedRenderBuffers.FindInOrder(aIndexEntries[i], RenderBufferOrderFunc);
+ if (indexEntry != KErrNotFound)
+ {
+ CHuiCanvasRenderBufferImage* entry = iCachedRenderBuffers[indexEntry];
+ iCachedRenderBuffers.Remove(indexEntry);
+ delete entry;
+ }
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CHuiCanvasTextureCache::SelectPreservedUnusedImageEntries(RPointerArray<CHuiCanvasGraphicImage>& aIndexEntries)
+ {
+ TInt totalUnusedTextureBytes = 0;
+
+ // Remove unused entries if they fit into the cache, leave last used ones in the cache if cache size allows
+ for(TInt i=aIndexEntries.Count() - 1; i >= 0; i--)
+ {
+ // Always delete bitmaps from unused entries, we can again duplicate pointers from handles when needed.
+ // Pointers are kept only for perfromance reasons.
+ CHuiCanvasGraphicImage* entry = aIndexEntries[i];
+
+ delete entry->iBitmap;
+ entry->iBitmap = NULL;
+
+ delete entry->iMask;
+ entry->iMask = NULL;
+
+ for (TInt j=0; j < entry->iSubImages.Count(); j++)
+ {
+ delete entry->iSubImages[j].iBitmap;
+ entry->iSubImages[j].iBitmap = NULL;
+
+ delete entry->iSubImages[j].iMask;
+ entry->iSubImages[j].iMask = NULL;
+ }
+
+ TSize textureSize = entry->iTexture->Size();
+ TInt textureEstimatedSizeInBytes = textureSize.iWidth * textureSize.iHeight * KHuiCanvasImageEstimatedBpp/8.f;
+
+ if (totalUnusedTextureBytes + textureEstimatedSizeInBytes < iUnusedCanvasImageTextureCacheSizeInKBytes*1024)
+ {
+ // Fits in the cache, remove from unused list, but keep zero size textures
+ if (textureEstimatedSizeInBytes != 0)
+ {
+ aIndexEntries.Remove(i);
+ }
+ }
+
+ totalUnusedTextureBytes += textureEstimatedSizeInBytes;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CHuiCanvasTextureCache::SelectPreservedUnusedTextEntries(RPointerArray<CHuiCanvasTextImage>& aIndexEntries)
+ {
+ TInt totalUnusedTextureBytes = 0;
+
+ // Remove unused entries if they fit into the cache, leave last used ones in the cache if cache size allows
+ for(TInt i=aIndexEntries.Count() - 1; i >= 0; i--)
+ {
+ TSize textureSize = aIndexEntries[i]->iTexture->Size();
+ TInt textureEstimatedSizeInBytes = textureSize.iWidth * textureSize.iHeight * KHuiCanvasTextEstimatedBpp/8.f;
+
+ if (totalUnusedTextureBytes + textureEstimatedSizeInBytes < iUnusedCanvasTextTextureCacheSizeInKBytes*1024)
+ {
+ // Fits in the cache, remove from unused list, but keep zero size textures
+ if (textureEstimatedSizeInBytes != 0)
+ {
+ aIndexEntries.Remove(i);
+ }
+ }
+
+ totalUnusedTextureBytes += textureEstimatedSizeInBytes;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CHuiCanvasTextureCache::SelectPreservedUnusedRenderBufferEntries(RPointerArray<CHuiCanvasRenderBufferImage>& aIndexEntries)
+ {
+ TInt totalUnusedRenderBufferBytes = 0;
+
+ // Remove unused entries if they fit into the cache, leave last used ones in the cache if cache size allows
+ for(TInt i=aIndexEntries.Count() - 1; i >= 0; i--)
+ {
+ CHuiCanvasRenderBufferImage* entry = aIndexEntries[i];
+ if (entry->iCanvasRenderBuffer)
+ {
+ TSize renderBufferSize = entry->iCanvasRenderBuffer->Size();
+ TInt renderBufferEstimatedSizeInBytes = renderBufferSize.iWidth * renderBufferSize.iHeight * KHuiCanvasRenderBufferEstimatedBpp/8.f;
+
+ if (totalUnusedRenderBufferBytes + renderBufferEstimatedSizeInBytes < iUnusedCanvasRenderBufferCacheSizeInKBytes*1024)
+ {
+ aIndexEntries.Remove(i);
+ }
+ totalUnusedRenderBufferBytes += renderBufferEstimatedSizeInBytes;
+ }
+ else
+ {
+#ifdef HUI_DEBUG_PRINT_CANVAS_TEXTURE_CACHE
+ RDebug::Print(_L("CHuiCanvasTextureCache::PurgeUnusedRenderBufferEntries: Non existing render buffer, Render does not support canvas render buffers ?"));
+#endif
+ }
+ }
+ }
+
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CHuiCanvasTextureCache::HandleOutOfTextureMemory()
+ {
+ RDebug::Print(_L("CHuiCanvasTextureCache::HandleOutOfTextureMemory: Out of memory happened !"));
+
+ DeleteAllReleasedEntries(EFalse);
+
+ // TODO: Who you gonna call when texture memory is full and we cannot ourself
+ // delete anymore textures ?
+ //
+ // Grim reaper ?!
+ //
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CHuiCanvasTextureCache::CalculateGraphicsMemoryUsage()
+ {
+ // TODO: This should handle NVG textures
+
+ if (iMaxTextureMemoryInKBytes)
+ {
+ // How much all alfred textures use memory currently, this include alf apps and all canvas textures
+ TInt totalUsedTextureMemoryInKBytes = CHuiStatic::Env().TextureManager().EstimatedTextureMemUsage(KHuiTextureEstimatedBpp) / 1024;
+
+ // How much there are unused textures cached currently
+ TInt totalUnusedCanvasTextureMemoryUsageInKBytes = CalculateUnusedCanvasTextureUsageInKbytes();
+
+ // Calculate how much there is space for unused textures
+ TInt availableCacheSizeInKBytes = iMaxTextureMemoryInKBytes - (totalUsedTextureMemoryInKBytes - totalUnusedCanvasTextureMemoryUsageInKBytes);
+
+ // Divide available space for unused textures between texts and images using defined ratio
+ if (availableCacheSizeInKBytes > 0)
+ {
+ iUnusedCanvasTextTextureCacheSizeInKBytes = availableCacheSizeInKBytes * KHuiCanvasUnusedTextImageCacheRatio;
+ iUnusedCanvasImageTextureCacheSizeInKBytes = availableCacheSizeInKBytes * (1.f - KHuiCanvasUnusedTextImageCacheRatio);
+ }
+ else
+ {
+ iUnusedCanvasTextTextureCacheSizeInKBytes = 0;
+ iUnusedCanvasImageTextureCacheSizeInKBytes = 0;
+ }
+ }
+ else
+ {
+ iUnusedCanvasTextTextureCacheSizeInKBytes = 0;
+ iUnusedCanvasImageTextureCacheSizeInKBytes = 0;
+ }
+
+ if (iMaxRenderBufferMemoryInKBytes)
+ {
+ // How much there are render buffers cached currently
+ TInt totalInKBytes = CalculateTotalCanvasRenderBufferUsageInKbytes();
+
+ // How much available for unused
+ TInt availableCacheSizeInKBytes = iMaxRenderBufferMemoryInKBytes - totalInKBytes;
+
+ if (availableCacheSizeInKBytes > 0)
+ {
+ iUnusedCanvasRenderBufferCacheSizeInKBytes = iMaxRenderBufferMemoryInKBytes - totalInKBytes;
+ }
+ else
+ {
+ iUnusedCanvasRenderBufferCacheSizeInKBytes = 0;
+ }
+ }
+ else
+ {
+ iUnusedCanvasRenderBufferCacheSizeInKBytes = 0;
+ }
+
+#ifdef HUI_DEBUG_PRINT_CANVAS_TEXTURE_CACHE
+ RDebug::Print(_L("-- CHuiCanvasTextureCache::CalculateTextureUsage: iUnusedCanvasTextTextureCacheSizeInKBytes = %i"), iUnusedCanvasTextTextureCacheSizeInKBytes);
+ RDebug::Print(_L("-- CHuiCanvasTextureCache::CalculateTextureUsage: iUnusedCanvasImageTextureCacheSizeInKBytes = %i"), iUnusedCanvasImageTextureCacheSizeInKBytes);
+ RDebug::Print(_L("-- CHuiCanvasTextureCache::CalculateTextureUsage: iUnusedCanvasRenderBufferCacheSizeInKBytes = %i"), iUnusedCanvasRenderBufferCacheSizeInKBytes);
+#endif
+ }
+
+void CHuiCanvasTextureCache::EnableTouchCountCheck(TBool aEnable)
+ {
+ iTouchCountCheckEnabled = aEnable;
+ }
+
+TBool CHuiCanvasTextureCache::IsTouchCountCheckEnabled()
+ {
+ return iTouchCountCheckEnabled;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TInt CHuiCanvasTextureCache::CalculateUnusedCanvasTextureUsageInKbytes()
+ {
+ // TODO: This should handle NVG textures
+
+ TInt totalUnusedTextureBytes = 0;
+
+ // Texts
+ RPointerArray<CHuiCanvasTextImage> textEntries;
+
+ FindUnusedTextEntries(textEntries);
+
+ for(TInt i=textEntries.Count() - 1; i >= 0; i--)
+ {
+ TSize textureSize = textEntries[i]->iTexture->Size();
+ totalUnusedTextureBytes += textureSize.iWidth * textureSize.iHeight * KHuiCanvasTextEstimatedBpp/8.f;
+ }
+
+ textEntries.Close();
+
+ // Images
+ RPointerArray<CHuiCanvasGraphicImage> imageEntries;
+
+ FindUnusedImageEntries(imageEntries);
+
+ for(TInt i=imageEntries.Count() - 1; i >= 0; i--)
+ {
+ TSize textureSize = imageEntries[i]->iTexture->Size();
+ totalUnusedTextureBytes += textureSize.iWidth * textureSize.iHeight * KHuiCanvasImageEstimatedBpp/8.f;
+ }
+
+ imageEntries.Close();
+
+ return totalUnusedTextureBytes/1024;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TInt CHuiCanvasTextureCache::CalculateUnusedCanvasRenderBufferUsageInKbytes()
+ {
+ TInt totalUnusedRenderBufferBytes = 0;
+
+ RPointerArray<CHuiCanvasRenderBufferImage> entries;
+
+ FindUnusedRenderBufferEntries(entries);
+
+ for(TInt i=entries.Count() - 1; i >= 0; i--)
+ {
+ if (iCachedRenderBuffers[i]->iCanvasRenderBuffer)
+ {
+ TSize renderBufferSize = entries[i]->iCanvasRenderBuffer->Size();
+ totalUnusedRenderBufferBytes += renderBufferSize.iWidth * renderBufferSize.iHeight * KHuiCanvasRenderBufferEstimatedBpp/8.f;
+ }
+ }
+
+ entries.Close();
+
+ return totalUnusedRenderBufferBytes/1024;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TInt CHuiCanvasTextureCache::CalculateTotalCanvasRenderBufferUsageInKbytes()
+ {
+ TInt totalRenderBufferBytes = 0;
+ for(TInt i=iCachedRenderBuffers.Count() - 1; i >= 0; i--)
+ {
+ if (iCachedRenderBuffers[i]->iCanvasRenderBuffer)
+ {
+ TSize renderBufferSize = iCachedRenderBuffers[i]->iCanvasRenderBuffer->Size();
+ totalRenderBufferBytes += renderBufferSize.iWidth * renderBufferSize.iHeight * KHuiCanvasRenderBufferEstimatedBpp/8.f;
+ }
+ }
+ return totalRenderBufferBytes/1024;
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+CHuiTexture* CHuiCanvasTextureCache::CreateRecycledTextureL()
+ {
+ CHuiTexture* texture = NULL;
+ if (iRecycledTextures.Count())
+ {
+ // If there are recycled textures, use one of those
+ TInt last = iRecycledTextures.Count() - 1;
+ texture = iRecycledTextures[last];
+ iRecycledTextures.Remove(last);
+ }
+ else
+ {
+ // No recycled textures available, create new one
+ texture = CHuiTexture::NewL();
+ }
+ return texture;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CHuiCanvasTextureCache::DeleteRecycledTexture(CHuiTexture* aTexture)
+ {
+ aTexture->Reset();
+
+ TInt error = KErrNone;
+
+ if (iRecycledTextures.Count() < KHuiMaxRecycledTextureCount)
+ {
+ error = iRecycledTextures.Append(aTexture);
+ if (error)
+ {
+ delete aTexture;
+ }
+ }
+ else
+ {
+ delete aTexture;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+CHuiCanvasRenderBuffer* CHuiCanvasTextureCache::CreateCachedRenderBufferL(const CHuiCanvasVisual& aUser, TSize aSizeHint)
+ {
+ if (IsLowMemoryStateEnabled())
+ {
+ // No canvas render buffers created in low memory state
+ return NULL;
+ }
+
+ TInt cachedEntry = KErrNotFound;
+ CHuiCanvasRenderBufferImage* newRenderBufferEntry = NULL;
+
+ iSearchedRenderBufferImageEntry->Reset();
+ iSearchedRenderBufferImageEntry->iOwner = (TAny*)&aUser;
+
+ cachedEntry = iCachedRenderBuffers.FindInOrder(iSearchedRenderBufferImageEntry, RenderBufferOrderFunc);
+
+ if (cachedEntry == KErrNotFound)
+ {
+ // Try first getting reused render buffer
+ newRenderBufferEntry = ReUseReleasedRenderBuffer(aSizeHint);
+
+ // Create new entry object if needed
+ if (!newRenderBufferEntry)
+ {
+ newRenderBufferEntry = new (ELeave) CHuiCanvasRenderBufferImage;
+ }
+
+ // Copy attributes (only iOwner attribute)
+ newRenderBufferEntry->iOwner = iSearchedRenderBufferImageEntry->iOwner;
+
+ CleanupStack::PushL(newRenderBufferEntry);
+
+ // Create new render buffer
+ if (!newRenderBufferEntry->iCanvasRenderBuffer)
+ {
+ newRenderBufferEntry->iCanvasRenderBuffer = iCanvasGc->CreateRenderBufferL(TSize(0,0));
+ }
+
+ // Insert to cache array
+ TInt insertSuccess = iCachedRenderBuffers.InsertInOrder(newRenderBufferEntry, RenderBufferOrderFunc);
+ __ASSERT_DEBUG( !insertSuccess, USER_INVARIANT() );
+ User::LeaveIfError( insertSuccess );
+
+ // We don't know which index it got, so look it up
+ cachedEntry = iCachedRenderBuffers.FindInOrder(newRenderBufferEntry, RenderBufferOrderFunc);
+
+ CleanupStack::Pop(newRenderBufferEntry);
+ }
+ else
+ {
+ // If it was found, great.
+ }
+
+ iCachedRenderBuffers[cachedEntry]->RefreshUser(aUser);
+
+ return iCachedRenderBuffers[cachedEntry]->iCanvasRenderBuffer;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+CHuiCanvasRenderBuffer* CHuiCanvasTextureCache::FindCachedRenderBuffer(const CHuiCanvasVisual& aUser)
+ {
+ TInt cachedEntry = KErrNotFound;
+
+ iSearchedRenderBufferImageEntry->Reset();
+ iSearchedRenderBufferImageEntry->iOwner = (TAny*)&aUser;
+
+ cachedEntry = iCachedRenderBuffers.FindInOrder(iSearchedRenderBufferImageEntry, RenderBufferOrderFunc);
+ if (cachedEntry != KErrNotFound)
+ {
+ iCachedRenderBuffers[cachedEntry]->RefreshUser(aUser);
+ return iCachedRenderBuffers[cachedEntry]->iCanvasRenderBuffer;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CHuiCanvasTextureCache::ReleaseCachedRenderBuffer(const CHuiCanvasVisual& aUser)
+ {
+ TInt cachedEntry = KErrNotFound;
+
+ iSearchedRenderBufferImageEntry->Reset();
+ iSearchedRenderBufferImageEntry->iOwner = (TAny*)&aUser;
+
+ cachedEntry = iCachedRenderBuffers.FindInOrder(iSearchedRenderBufferImageEntry, RenderBufferOrderFunc);
+ if (cachedEntry != KErrNotFound)
+ {
+ CHuiCanvasRenderBufferImage* releasedEntry = iCachedRenderBuffers[cachedEntry];
+ iCachedRenderBuffers.Remove(cachedEntry);
+ releasedEntry->RemoveUser(aUser);
+ releasedEntry->iOwner = releasedEntry; // No real owner anymore, se it self as owner
+
+ if(!IsLowMemoryStateEnabled())
+ {
+ // re-insert released entry (new position in the array order because we clered iOwner)
+ TInt insertSuccess = iCachedRenderBuffers.InsertInOrder(releasedEntry, RenderBufferOrderFunc);
+
+ if (insertSuccess != KErrNone)
+ {
+ // oh no re-insert failed, now we must delete the entry to avoid memory leak.
+ delete releasedEntry;
+ }
+ }
+ else
+ {
+ delete releasedEntry;
+ }
+
+ iHasReleasedRenderBuffers = ETrue;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+CHuiCanvasRenderBufferImage* CHuiCanvasTextureCache::ReUseReleasedRenderBuffer(TSize aSizeHint)
+ {
+ if (aSizeHint == TSize(0,0))
+ {
+ return NULL;
+ }
+
+ for(TInt i=iCachedRenderBuffers.Count() - 1; i >= 0; i--)
+ {
+ // Check if there are any released buffers with have requested size
+ if (!iCachedRenderBuffers[i]->IsAnyUser() &&
+ iCachedRenderBuffers[i]->iCanvasRenderBuffer &&
+ iCachedRenderBuffers[i]->iCanvasRenderBuffer->Size() == aSizeHint)
+ {
+ // Remove from array and return instance to caller
+ CHuiCanvasRenderBufferImage* reusedEntry = iCachedRenderBuffers[i];
+ iCachedRenderBuffers.Remove(i);
+ return reusedEntry;
+ }
+ }
+
+ return NULL;
+ }
+
+void CHuiCanvasTextureCache::EnableLowMemoryState(TBool aEnable)
+ {
+ // deprecated
+ }
+
+THuiMemoryLevel CHuiCanvasTextureCache::MemoryLevel()
+ {
+ return iMemoryLevel;
+ }
+
+void CHuiCanvasTextureCache::SetMemoryLevel(THuiMemoryLevel aLevel)
+ {
+ iMemoryLevel = aLevel;
+
+ if (iMemoryLevel <= EHuiMemoryLevelLowest)
+ {
+#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
+RDebug::Print(_L("-- CHuiCanvasTextureCache::SetMemoryLevel: Enabling lowest memory state"));
+#endif
+
+ // Set cache sizes to minimum
+ iMaxTextureMemoryInKBytes = 0;
+ iMaxRenderBufferMemoryInKBytes = 0;
+
+ // Delete images, even if they are in use
+ for(TInt i=iCachedImages.Count() - 1; i >= 0; i--)
+ {
+ CHuiCanvasGraphicImage* entry = iCachedImages[i];
+ iCachedImages.Remove(i);
+ delete entry;
+ }
+
+ // Delete texts, even if they are in use
+ for(TInt i=iCachedTexts.Count() - 1; i >= 0; i--)
+ {
+ CHuiCanvasTextImage* entry = iCachedTexts[i];
+ iCachedTexts.Remove(i);
+ delete entry;
+ }
+
+
+ // Delete canvas render buffers, even if they are in use
+ for(TInt i=iCachedRenderBuffers.Count() - 1; i >= 0; i--)
+ {
+ CHuiCanvasRenderBufferImage* entry = iCachedRenderBuffers[i];
+ iCachedRenderBuffers.Remove(i);
+ delete entry;
+ }
+ }
+ else if (iMemoryLevel <= EHuiMemoryLevelLow)
+ {
+ #ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
+ RDebug::Print(_L("-- CHuiCanvasTextureCache::SetMemoryLevel: Enabling low memory state"));
+ #endif
+ // Set cache sizes to minimum
+ iMaxTextureMemoryInKBytes = 0;
+ iMaxRenderBufferMemoryInKBytes = 0;
+
+ // Set flags to make sure we check all entries
+ iHasReleasedTexts = ETrue;
+ iHasReleasedImages = ETrue;
+ iHasReleasedRenderBuffers = ETrue;
+
+ // Delete released cached entries
+ DeleteAllReleasedEntries(EFalse);
+
+ // Delete canvas render buffers, even if they are in use
+ for(TInt i=iCachedRenderBuffers.Count() - 1; i >= 0; i--)
+ {
+ CHuiCanvasRenderBufferImage* entry = iCachedRenderBuffers[i];
+ iCachedRenderBuffers.Remove(i);
+ delete entry;
+ }
+ }
+ else
+ {
+ #ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
+ RDebug::Print(_L("-- CHuiCanvasTextureCache::SetMemoryLevel: Disabling low memory state"));
+ #endif
+
+ // TODO: This could be configurable cenrep or something ?
+ iMaxTextureMemoryInKBytes = KHuiMaxRecommendedTextureAmountInKBytes;
+ iMaxRenderBufferMemoryInKBytes = KHuiMaxRecommendedRenderBufferAmountInKBytes;
+ }
+ }
+
+TBool CHuiCanvasTextureCache::IsLowMemoryStateEnabled() const
+ {
+ if (iMemoryLevel < EHuiMemoryLevelReduced)
+ {
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+ }