uiacceltk/hitchcock/coretoolkit/src/HuiCanvasTextureCache.cpp
changeset 0 15bf7259bb7c
child 3 d8a3531bc6b8
child 13 8f67d927ea57
--- /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;        
+        }
+    }