uiacceltk/hitchcock/coretoolkit/src/huicanvaswspainter.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:16:53 +0100
branchRCL_3
changeset 20 31fccae4f8a7
parent 19 e5af45d51884
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* Copyright (c) 2007-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:   Definition of CHuiCanvasWsPainter.
*
*/



#include "huicanvaswspainter.h"

#include "uiacceltk/HuiCanvasVisual.h"
#include "HuiRenderPlugin.h"
#include "uiacceltk/HuiGc.h"
#include "uiacceltk/HuiPanic.h"
#include "uiacceltk/HuiUtil.h"
#include "uiacceltk/HuiStatic.h"
#include "uiacceltk/HuiEnv.h"
#include "uiacceltk/HuiControl.h"
#include "uiacceltk/HuiVisual.h"
#include "uiacceltk/HuiTextMesh.h"
#include "uiacceltk/HuiCanvasCmdBufferReader.h"
#include "huicanvasgc.h"
#include "huicanvaswsgc.h"
#include "HuiRenderSurface.h"
#include "huicanvastexturecache.h"
#include "huicanvasbackground.h"
#include "huicanvaswsswgc.h"
#include "huicanvasdebugwsgc.h"
#include "huicanvaswsbitgc.h"
#include "../../CommonInc/huiwscanvascommands.h"
#include <graphics/wsgraphicscontext.h>

#ifdef HUI_DEBUG_TRACK_DRAWING
#include "alfloggingconfiguration.h"
#include "alfcommanddebug.h"
#include "huistatictlsdata.h"
#endif
#include <e32cmn.h>
#include <AknLayoutFont.h>
#include <graphics/lookuptable.h>

#include "HuiCmdBufferBrush.h"

#include "alfmoduletestconf.h"
#ifdef USE_MODULE_TEST_HOOKS_FOR_ALF
    // Provides TLS object data for test cases.
    // This is used only if module test hooks are set on.
    #include "huistatictlsdata.h"
#endif // USE_MODULE_TEST_HOOKS_FOR_ALF
// Provides module test hook defines.
#include "alfmoduletestdefines.h"

/** 
 * Constants to define enabling/disabling render buffer automatically 
 *  incase there are frequently new buffers posted. 
 * 
 *  This may improve performance in some HW platforms.
 * 
 */
const TBool KHuiCanvasAutomaticRenderBufferUsage = EFalse; // Disbaled until all UI isses has been solved  
const TInt KHuiCanvasDisableRenderBufferHandleInterval = 100; // Milliseconds 
const TInt KHuiCanvasEnableRenderBufferHandleInterval = 500;  // Milliseconds

/** ETrue - use SelectGcL to select gc implementation, 
    EFalse - use KHuiDefaultCanvasWsGc. */
const TBool KHuiUseSelectGc = ETrue;

/** Change this to select default rendering ws gc implementation.
    Only used when KHuiUseSelectGc does not hold. */
const THuiCanvasWsGcType KHuiDefaultCanvasWsGc = EHuiCanvasWsHw;

//#define HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL

CHuiCanvasWsPainter* CHuiCanvasWsPainter::NewL()
	{
	CHuiCanvasWsPainter* self    = new ( ELeave ) CHuiCanvasWsPainter;
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop();
	return self;
    }


CHuiCanvasWsPainter::CHuiCanvasWsPainter()
    {
    }

void CHuiCanvasWsPainter::ConstructL()
    {
    CHuiStatic::Env().AddMemoryLevelObserver(this);
    iWsCommandBufferReader = NULL;
    iPartialCommandBuffer = NULL;
    iCacheCleared = EFalse;

    if ( KHuiUseSelectGc )
        {
        SelectGcL();
        }
    else if (KHuiDefaultCanvasWsGc == EHuiCanvasWsHw)
        {
        iCanvasWsHwGc = CHuiCanvasWsHwGc::NewL();
        iCanvasWsGc = iCanvasWsHwGc;        
        }
    else if (KHuiDefaultCanvasWsGc == EHuiCanvasWsSw)
        {
        iCanvasWsSwGc = CHuiCanvasWsSwGc::NewL();
        iCanvasWsGc = iCanvasWsSwGc;            
        }    
    else if (KHuiDefaultCanvasWsGc == EHuiCanvasWsBit)
        {
        iCanvasWsBitGc = CHuiCanvasWsBitGc::NewL();
        iCanvasWsGc = iCanvasWsBitGc;            
        }    
    else
        {
        // Never happens, right.
        }
    
    iWsCommandBufferReader = new (ELeave) CHuiCanvasCmdBufferReader(); 
    
    #ifdef HUI_DEBUG_TRACK_DRAWING
    if (!iCanvasDebugWsGc)
        {
        iCanvasDebugWsGc = CHuiCanvasDebugWsGc::NewL( iCanvasWsGc, *TTlsData::CommandDebugger() );
        iCanvasWsGc = iCanvasDebugWsGc;
        }
    
    #endif
    }


CHuiCanvasWsPainter::~CHuiCanvasWsPainter()
    {
    if (iCanvasVisual)
        {
        iCanvasVisual->Env().RemoveMemoryLevelObserver(this);
        }
    else
        {
        CHuiStatic::Env().RemoveMemoryLevelObserver(this);
        }
    
    ClearCommandSet();	
    delete iWsCommandBufferReader;	
    delete iCanvasWsHwGc;
    delete iCanvasWsSwGc;
    delete iCanvasWsBitGc;

    iTempRegion.Close();
    iTempCurrentSubRegion.Close();
    iTempIntersectingRegion.Close();
#ifdef HUI_DEBUG_TRACK_DRAWING
    delete iCanvasDebugWsGc;
#endif
    iFullUpdateRegion.Close();
    iShapeRegion.Close();
    }
    

CHuiGc::TOrientation CHuiCanvasWsPainter::CalculateRelativeOrientation()
    {
    // Calculate drawing command rotation as relative to the current display rotation.
    // It may be that drawing commands has been sent when display was in different rotation.
    TInt last = iCommandBuffers.Count() - 1;
    CHuiGc::TOrientation relativeOrientation = CHuiGc::EOrientationNormal;    
    CHuiGc::TOrientation displayOrientation = CHuiStatic::Env().PrimaryDisplay().Orientation(); 
    CHuiGc::TOrientation drawingCommandOrientation = iCommandBuffers[last]->iOrientation; 
    
    TInt rotationAngle[] =
        {
        0, 
        270, 
        90, 
        180
        };
        
    TInt displayOrientationAngle = rotationAngle[displayOrientation];
    TInt drawingCommandOrientationAngle = rotationAngle[drawingCommandOrientation];    
    TInt relativeOrientationAngle = drawingCommandOrientationAngle - displayOrientationAngle;
    
    // Check over/underflow
    if (relativeOrientationAngle > 360)
        {
        relativeOrientationAngle -= 360;
        }
    else if (relativeOrientationAngle < 0)
        {
        relativeOrientationAngle += 360;
        }
    
    switch (relativeOrientationAngle)
        {
        case 0:
            {
            relativeOrientation = CHuiGc::EOrientationNormal;
            break;
            }
        case 90:
            {
            relativeOrientation = CHuiGc::EOrientationCW90;            
            break;
            }
        case 270:
            {
            relativeOrientation = CHuiGc::EOrientationCCW90;            
            break;
            }
        case 180:
            {
            relativeOrientation = CHuiGc::EOrientation180;            
            break;
            }
        default:
            {
            // As usual, this should not happen...but just in case it does use normal rotation
            relativeOrientation = CHuiGc::EOrientationNormal;
            break;
            }        
        }
    return relativeOrientation;
    }

void CHuiCanvasWsPainter::HandleBufferL(TRect& aDisplayRect, TInt aAction, const CHuiCanvasVisual& aUser, CHuiGc* aGc, TPoint aPos ) 
    {   
	#ifdef __ALF_SYMBIAN_RWINDOW_CLEARING_BUG_WORKAROUND__
    iTestFullDisplayRect = aDisplayRect;
	#endif
    
    // Store user so that we can clear cache later
    iCanvasVisual = (CHuiCanvasVisual*)&aUser;

    // Let canvas know about user and gc
    CHuiCanvasGc& canvasGc = iCanvasWsGc->CanvasGc();
    canvasGc.SetVisual(aUser);
    if (aGc)
        {
        canvasGc.SetGc(*aGc);
        }
    
    if (iCommandBuffers.Count() != 0)
        {
#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
        RDebug::Print(_L(">> CHuiCanvasWsPainter::HandleBufferL this = %i, Action = %i"), this, aAction );
        TTime startTime;
        startTime.UniversalTime();
#endif

        // Initialize canvas
        canvasGc.SetDefaults();   

        // Ensure that all regions have been shifted to correct origin (before calculating iFullUpdateRegion).
        UpdateBufferUpdateRegions(aPos);
        
        // Make sure we got up to date update reagion
        iFullUpdateRegion.Clear();                
        TInt bufferCount = iCommandBuffers.Count();
        for (TInt cb = 0; cb < bufferCount; cb++)
            {        
            iFullUpdateRegion.Union(iCommandBuffers[cb]->iUpdateRegion);
            }
        iFullUpdateRegion.Tidy();
        
#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
        const TRect updateRegionBoundingRect = iFullUpdateRegion.BoundingRect();        
        RDebug::Print(_L(">> CHuiCanvasWsPainter::HandleBufferL iFullUpdateRegion.BoundingRect() = (%i,%i) (%i,%i)"), 
                updateRegionBoundingRect.iTl.iX,
                updateRegionBoundingRect.iTl.iY,
                updateRegionBoundingRect.iBr.iX,
                updateRegionBoundingRect.iBr.iY
                );

        if (iCanvasWsGc->Type() == EHuiCanvasWsSw)
            {
            RDebug::Print(_L(">> CHuiCanvasWsPainter::HandleBufferL - SW mode is used."));
            }
        else if (iCanvasWsGc->Type() == EHuiCanvasWsBit)
            {
            RDebug::Print(_L(">> CHuiCanvasWsPainter::HandleBufferL - BITGC mode is used."));
            }
        
        if (aUser.Effect())
            {
            RDebug::Print(_L(">> CHuiCanvasWsPainter::HandleBufferL - visual has EFFECT"));
            }
        
        
#endif
        
        if (aAction == EDrawBuffer)
            {
            /* Check and enable render buffer if needed */
            EnableRenderBufferIfNeeded(ETrue);

            // Compenstate possible orientation mismatch between drawing commands and display orientation
            // by letting iCanvasWsGc know about it. Mismatch usually happens when screen is rotated and
            // it may cause visually unpleasent things at the screen.
            CHuiGc::TOrientation relativeOrientation = CalculateRelativeOrientation();
            iCanvasWsGc->SetRelativeOrientation(relativeOrientation);
            #ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
            RDebug::Print(_L(">> CHuiCanvasWsPainter::HandleBufferL - relativeOrientation = %i "), relativeOrientation);    
            #endif
            
            /* If window shape region has been changed, we should clear the window to get rid of old content. 
             * We also set all command buffers to "not drawn" state so that everything will be redrawn.
             * Actual clearing is done after BeginActionL, because drawing phase will start only after calling it.
             */
            if(iShapeRegionClearingPending)
                {
                // Cause a full redraw for the canvas visual
                SetAllBuffersChanged(ETrue);    
                ClearAllBufferStatusFlags(EHuiCanvasBufferStatusDrawn);
                }
            
            
            /* Check if we have buffers that are not yet been drawn (or we render buffer is disabled) */
            TBool cachePrepared = !HasCommandBuffersWithoutFlags(EHuiCanvasBufferStatusDrawn) || !iCanvasWsGc->IsRenderBufferEnabled();

            /* Begin draw. If render buffer is used this sets up the render buffer if needed */
            iCanvasWsGc->BeginActionL(aAction,aDisplayRect,aUser,cachePrepared,iFullUpdateRegion);                   

            if(iShapeRegionClearingPending)
                {
                #ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
                    RDebug::Print(_L(">> CHuiCanvasWsPainter::HandleBufferL - Clearing fullupdateregion"));    
                #endif
                // Clear the window update region area
                TBool doClear = ETrue;
                iCanvasWsGc->EnableUpdateRegion(iFullUpdateRegion, doClear);
                iCanvasWsGc->DisableUpdateRegion(); 
                iShapeRegionClearingPending = EFalse;
                }

            #ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
            if (iCanvasWsGc->IsRenderBufferEnabled())
                {
                RDebug::Print(_L(">> CHuiCanvasWsPainter::HandleBufferL renderbuffer is ENABLED"));
                }
            else
                {
                RDebug::Print(_L(">> CHuiCanvasWsPainter::HandleBufferL renderbuffer is DISABLED"));
                }
            #endif
            
            /* We do not ignore unchanged buffers currently */
            TBool ignoreUnChangedBuffers = EFalse; 

            /* We can ignore buffers that only update areas which get clipped */
            TBool ignoreClippedBuffers = ETrue;            
            if (relativeOrientation != CHuiGc::EOrientationNormal)
                {
                ignoreClippedBuffers = EFalse;
                }
            
            /* We can ignore buffers that has previously already been drawn into render buffer */
            TBool ignoreHandledBuffers = iCanvasWsGc->IsRenderBufferEnabled() && iCanvasWsGc->IsRenderBufferInitialized();                    

            
            /* 
             * We need to clear area if render buffer is used because otherwise it will cause dimming for semitransparent areas.
             * 
             * NOTE1: We do not clear if the window is opaque. This is a bit questionable, but Avkon seems to rely
             * quite much on luck with its drawing and there are areas in the windows which are not always covered
             * by drawing commands, thus random garabage from previous frames would be visible if such window
             * update area would always be cleared.
             * 
             * NOTE2: We handle window that has background clearing enabled similarly as transparent window
             *        because their wanted behaviour is similar to transparent window (user wants to see the stuff
             *        behind window drawing commands and may want to draw commands translucently). 
             *        
             * -> So always clear if drawing vie render buffer and window is transparent or has backround.       
             *        
             */            
            TBool clearBeforeHandlingBuffer = iCanvasWsGc->IsRenderBufferEnabled() 
                && (!(aUser.Flags() & EHuiVisualFlagOpaqueHint) || aUser.IsBackgroundDrawingEnabled());

                        
            // TODO: Should avoid trap, but EndActionL must always be called
            TRAPD(err, DoHandleAllBuffersL( aDisplayRect, aAction, aUser, aGc, aPos, 
                    ignoreUnChangedBuffers, 
                    ignoreClippedBuffers,
                    ignoreHandledBuffers,
                    clearBeforeHandlingBuffer));
            
            if (err != KErrNone)
                {
                RDebug::Print(_L("CHuiCanvasWsPainter::HandleBufferL(): draw error = %i "), err);
                RenewAllBuffers();
                }
            
            // Workaround for fact that WSERV sends command buffers that do not contain real drawing commands.
            // If there are no real drawing commnads, just avoid display update at the EndAction so that
            // we don't write empty pixels to screen and cause flicker. 
            TBool updateDisplay = HasCommandBuffers(EHuiCanvasBufferContainsDrawing);
            
            /* End draw. If render buffer is in use, this will update the screen */
            iCanvasWsGc->EndActionL(iFullUpdateRegion, updateDisplay);                 
            
            /* Mark that cache is not more clear */
            iCacheCleared = EFalse;
            }
        else if (aAction == EScanBuffer)
            {
            /* Check and enable render buffer if needed */
            EnableRenderBufferIfNeeded(ETrue);
            
            /* Check if we have buffers that are not yet prepared (or we render buffer is disabled) */
            TBool cachePrepared = !HasCommandBuffersWithoutFlags(EHuiCanvasBufferStatusScanned) || !iCanvasWsGc->IsRenderBufferEnabled();

            /* Begin scan. If render buffer is used this sets up the render buffer if needed */
            iCanvasWsGc->BeginActionL(aAction,aDisplayRect,aUser,cachePrepared,iFullUpdateRegion);    

            #ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
            if (iCanvasWsGc->IsRenderBufferEnabled())
                {
                RDebug::Print(_L(">> CHuiCanvasWsPainter::HandleBufferL renderbuffer is ENABLED"));
                }
            else
                {
                RDebug::Print(_L(">> CHuiCanvasWsPainter::HandleBufferL renderbuffer is DISABLED"));
                }
            #endif
            
            /* We do not ignore unchanged buffers currently */
            TBool ignoreUnChangedBuffers = EFalse;
            
            /* We do not ignore clipped buffers as they possibly contain items that may soon appear on the screen */
            TBool ignoreClippedBuffers = EFalse;                    
            
            /* We can ignore buffers that has previously already been scanned */
            TBool ignoreHandledBuffers = ETrue;     

            /* No need to clear area if scanning */
            TBool clearBeforeHandlingBuffer = EFalse;
            
            // TODO: Should avoid trap, but EndActionL must always be called
            TRAPD(err, DoHandleAllBuffersL( aDisplayRect, aAction, aUser, aGc, aPos, 
                    ignoreUnChangedBuffers, 
                    ignoreClippedBuffers,
                    ignoreHandledBuffers,
                    clearBeforeHandlingBuffer));    
            
            if (err != KErrNone)
                {
                RDebug::Print(_L("CHuiCanvasWsPainter::HandleBufferL(): scan error = %i "), err);
                RenewAllBuffers();
                }
            
            /* End draw. If render buffer is in use, this will update the screen */
            iCanvasWsGc->EndActionL(iFullUpdateRegion, EFalse);

            /* Mark that cache is not more clear */
            iCacheCleared = EFalse;
            
            /* Update dirty area to aDisplayRect in case this action is originated from dirty area scan */
            aDisplayRect = DirtyRect();
            }
            
                        
#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
        TTime endTime;
        endTime.UniversalTime();
        TInt timeInMs =  endTime.MicroSecondsFrom( startTime ).Int64()/1000;           
        RDebug::Print(_L(">> CHuiCanvasWsPainter::HandleBufferL took %i ms"), timeInMs);
#endif
        }
        
    }

void CHuiCanvasWsPainter::DoHandleAllBuffersL( TRect& aDisplayRect, 
                                               TInt aAction, 
                                               const CHuiCanvasVisual& aUser, 
                                               CHuiGc* aGc, 
                                               TPoint& aPos, 
                                               TBool aIgnoreUnChangedBuffers, 
                                               TBool aIgnoreClippedBuffers, 
                                               TBool aIgnoreHandledBuffers,
                                               TBool aClearBeforeHandlingBuffers) 
    {
    TInt bufferCount = iCommandBuffers.Count();
    for (TInt cb = 0; cb < bufferCount; cb++)
        {
        CHuiCanvasCommandBuffer* cmdbuffer = iCommandBuffers[cb];

        #ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
        RDebug::Print(_L(">> CHuiCanvasWsPainter::DoHandleAllBuffersL Buffer size: %i "), iCommandBuffers[cb]->iCommands->Size());                
        for (TInt k=0; k < cmdbuffer->iUpdateRegion.Count();k++)
            {
            RDebug::Print(_L(">> CHuiCanvasWsPainter::DoHandleAllBuffersL Buffer region rect: %i,%i, %i,%i "), 
                cmdbuffer->iUpdateRegion[k].iTl.iX,
                cmdbuffer->iUpdateRegion[k].iTl.iY,
                cmdbuffer->iUpdateRegion[k].iBr.iX,
                cmdbuffer->iUpdateRegion[k].iBr.iY);                
            }
        #endif

        if (aIgnoreUnChangedBuffers && !cmdbuffer->iChanged)
            {
            #ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
            RDebug::Print(_L(">> CHuiCanvasWsPainter::DoHandleAllBuffersL Skipping buffer, it has not changed"));                
            #endif            
            continue;            
            }

        if (aIgnoreHandledBuffers)
            {
            if (aAction == EDrawBuffer && (cmdbuffer->iStatusFlags & EHuiCanvasBufferStatusDrawn))
                {
                #ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
                RDebug::Print(_L(">> CHuiCanvasWsPainter::DoHandleAllBuffersL Skipping buffer, it has already been drawn."));                
                #endif                            
                continue;
                }
            else if (aAction == EScanBuffer && (cmdbuffer->iStatusFlags & EHuiCanvasBufferStatusScanned))
                {
                #ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
                RDebug::Print(_L(">> CHuiCanvasWsPainter::DoHandleAllBuffersL Skipping buffer, it has already been scanned."));                
                #endif            
                continue;            
                }
            else
                {
                // No, we dont ignore.                                
                }
            }
            
        if (aIgnoreClippedBuffers && IsBufferCompletelyOutisideClippingRegion(*cmdbuffer))
            {
            #ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
            RDebug::Print(_L(">> CHuiCanvasWsPainter::DoHandleAllBuffersL: Skipping buffer %i, as it is completely clipped"), cb);
            #endif                    
            continue;
            }
              
        if (aGc)
            {
            #ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
            RDebug::Print(_L(">> CHuiCanvasWsPainter::DoHandleAllBuffersL ClipRegion before clipping to updateregion:"));                
            const TRegion& originalclipregion = aGc->ClipRegion(); 
            for (TInt k=0; k < originalclipregion.Count();k++)
                {
                
                RDebug::Print(_L(">> CHuiCanvasWsPainter::DoHandleAllBuffersL original clip region rect: %i,%i, %i,%i "), 
                        originalclipregion[k].iTl.iX,
                        originalclipregion[k].iTl.iY,
                        originalclipregion[k].iBr.iX,
                        originalclipregion[k].iBr.iY);                
                }
            #endif

            
            // If buffers has been scanned, but it does not seem to contain any real drawing commands we discard it            
            if (!(cmdbuffer->iStatusFlags & EHuiCanvasBufferContainsDrawing) && (cmdbuffer->iStatusFlags & EHuiCanvasBufferStatusScanned))
                {
                #ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
                RDebug::Print(_L("CHuiCanvasWsPainter::DoHandleAllBuffersL: Hmmm, WSERV has sent buffer without real drawing commands."), cb);
                #endif
                continue;
                }
            
            // Clip drawing to update area. This seems to improve performance although
            // it may depend on used HW.

            // Set position delta to zero, otherwise updateregion is adjusted incorrectly
            // in SW mode. No effect on HW mode as it does not adjust the updateregion in
            // EnableUpdateRegion call...
            TPoint delta(0,0);
            iCanvasWsGc->SetPositionDelta(delta);
            iCanvasWsGc->EnableUpdateRegion(iCommandBuffers[cb]->iUpdateRegion, aClearBeforeHandlingBuffers);

            #ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
            RDebug::Print(_L(">> CHuiCanvasWsPainter::DoHandleAllBuffersL ClipRegion after clipping to updateregion:"));                
            const TRegion& clipregion = aGc->ClipRegion(); 
            for (TInt k=0; k < originalclipregion.Count();k++)
                {
                
                RDebug::Print(_L(">> CHuiCanvasWsPainter::DoHandleAllBuffersL current clip region rect: %i,%i, %i,%i "), 
                        clipregion[k].iTl.iX,
                        clipregion[k].iTl.iY,
                        clipregion[k].iBr.iX,
                        clipregion[k].iBr.iY);                
                }
            #endif
            
            TRAPD(error, DoHandleBufferL(cb, aDisplayRect, aAction, aUser, aGc, aPos ));
            
            if (error)
                {
                #ifdef _DEBUG
                RDebug::Print(_L("CHuiCanvasWsPainter::DoHandleAllBuffersL: Error in buffer %i, continuing."), cb);
                #endif
                }
            
            iCanvasWsGc->DisableUpdateRegion();
            }
        else
            {
            DoHandleBufferL(cb, aDisplayRect, aAction, aUser, aGc, aPos);
            }
        
        // Update buffer status
        if (aAction == EDrawBuffer)
            {
            cmdbuffer->SetStatusFlags(EHuiCanvasBufferStatusDrawn);
            }
        else if (aAction == EScanBuffer)
            {
            cmdbuffer->SetStatusFlags(EHuiCanvasBufferStatusScanned);            
            }
        else
            {
            // This should not happen
            }
        }         
    }


void CHuiCanvasWsPainter::HandleBufferL(TRect& aDisplayRect, TInt aAction, const CHuiCanvasVisual& aUser, CHuiGc* aGc, TPoint aPos, TPtrC8 aCommands, CHuiCanvasCommandBuffer * /*buf*/)
    {
    TUint8 *ptr = const_cast<TUint8*>(aCommands.Ptr());
    TInt length = aCommands.Length();
    TPtr8 cmds(ptr, length, length);
    CHuiCanvasCommandBuffer *buf = new (ELeave)CHuiCanvasCommandBuffer;
    CleanupStack::PushL(buf);
    buf->iUpdateRegion.AddRect(aDisplayRect);
    if (iCanvasVisual && iCanvasVisual->Display())
        {
        buf->iOrientation = iCanvasVisual->Display()->Orientation();
        }
    DoHandleBufferStringL(-1, aDisplayRect, aAction, aUser, aGc, aPos, cmds, buf);
    CleanupStack::PopAndDestroy();
    }

void CHuiCanvasWsPainter::DoPeekBufferAndUpdateShapeRegionL()
    {
    TBool hadShapeRegion = iShapeRegionAvailable;
    iShapeRegionAvailable = EFalse;
    
    TInt latest = iCommandBuffers.Count() - 1;    
    DoPeekBufferL(latest);
    
    if (hadShapeRegion && !iShapeRegionAvailable)
        {
        // Previously we had shape region, but not any more.
        // So refresh update regions.
        iShapeRegionClearingPending = ETrue;
        iShapeRegionClippingPending = ETrue;        
        }
    }

void CHuiCanvasWsPainter::DoPeekBufferL(TInt aIndex) 
    {   
    RMemReadStream& readerStream = iWsCommandBufferReader->Stream();
    CHuiCanvasCommandBuffer& commandBuffer = *iCommandBuffers[aIndex];
    HBufC8* cmdBuf = commandBuffer.iCommands;
    TInt bufLength =  cmdBuf->Length();
    
    TPtr8 des = cmdBuf->Des();
    iWsCommandBufferReader->Init( des, bufLength );
    TInt offset = 0; 
    TInt command = 0;
    TBool donePeeking = EFalse;
    do
        {
        command = readerStream.ReadUint8L();
        
        switch ( command )
            {
            case EAlfFrameContainsUnsupportedCommands:
                {
                TUint8 containsUnsupportedCommands = iWsCommandBufferReader->Stream().ReadUint8L();
                if ( containsUnsupportedCommands )
                    {
                    commandBuffer.iContainsUnsupportedCommands = ETrue;
                    }
                break;
                }
            case EAlfFrameFlags:
                {
                TInt flags;
                iWsCommandBufferReader->ReadInt32L( flags );
                if (flags & EAlfTransparentContent)
                    {
                    EnableRenderBuffer(ETrue);
                    }                
                break;
                }
            case EAlfFrameOrientation:
                {
                TInt orientation;
                iWsCommandBufferReader->ReadInt32L(orientation);
                commandBuffer.iOrientation = (CHuiGc::TOrientation)orientation;
                break;
                }
                           
            case EAlfSetUpdateRegion: 
                {
                WsSetUpdateRegionL(aIndex);
				commandBuffer.iPositionForUpdateRegion = Visual()->DisplayRect().iTl.Round();
                break;
                }
            case EAlfCommandIndexArrayHeader:
                {
                TInt tmp;
                iWsCommandBufferReader->ReadInt8L(); // padding
                iWsCommandBufferReader->ReadInt32L( tmp );
                iWsCommandBufferReader->ReadInt32L( tmp );
                break;
                }
            case EAlfPacketPadding:
                {
                DoDigestPaddingL();
				break;
                }
            case EAlfSetShapeRegion: 
                {
                WsSetShapeRegionL( aIndex );
                break;
                }
            default:
                {
                donePeeking = ETrue;
                break;    
                }     
            }
        
   		offset = readerStream.Source()->TellL( MStreamBuf::ERead ).Offset();
       	
        } while( offset < bufLength && !donePeeking);
    
    iCommandBuffers[aIndex]->iOriginalDisplayRect = iCanvasVisual->DisplayRect();
    }


#ifdef HUI_DEBUG_TRACK_DRAWING
void CHuiCanvasWsPainter::DoHandleBufferL(TInt aIndex, TRect& aDisplayRect, TInt aAction, const CHuiCanvasVisual& aUser, CHuiGc* aGc, TPoint& aPos) 
#else
void CHuiCanvasWsPainter::DoHandleBufferL(TInt aIndex, TRect& aDisplayRect, TInt aAction, const CHuiCanvasVisual& aUser, CHuiGc* aGc, TPoint& aPos) 
#endif
    {
    CHuiCanvasCommandBuffer* commandBuffer = iCommandBuffers[aIndex];
    HBufC8* cmdBuf = commandBuffer->iCommands;

#ifdef HUI_DEBUG_TRACK_DRAWING
    if ( commandBuffer->iTrackedBuffer )
        {
        RDebug::Print( _L("CHuiCanvasWsPainter::DoHandleBufferL - Tracked buffer found"));
        switch ( aAction )
            {
            case EDrawBuffer:
                {
                RDebug::Print( _L("CHuiCanvasWsPainter::DoHandleBufferL - draw buffer"));
                break;
                }
            case EScanBuffer:
                {
                RDebug::Print( _L("CHuiCanvasWsPainter::DoHandleBufferL - scan buffer"));
                break;
                }
            default:;
            }
        }

    TTlsData::CommandDebugger()->StartFrame();
    if ( commandBuffer->iProcessName )
        {
        // UNCOMMENT THIS IF YOU WANT TO PRINT EVERYTHING
        // iCommandDebugger->SetPrint( ETrue );
        // UNCOMMENT THIS IF YOU WANT PRINTS ONLY FOR CERTAIN PROCESS!
        // DEFINE PROCESS NAME IN alfcommanddebug.cpp
        // iCommandDebugger->SetPrint( iCommandDebugger->TrackProcess( commandBuffer->iProcessName ) );
        RDebug::Print(_L("CHuiCanvasWsPainter::DoHandleBufferL - Process [%S]"), commandBuffer->iProcessName );
        }
    else
        {
//        RDebug::Print(_L("CHuiCanvasWsPainter::DoHandleBufferL - Process [already dead or not found]"));
        }
#endif
  
    TPtr8 des = cmdBuf->Des();
    DoHandleBufferStringL(aIndex, aDisplayRect, aAction, aUser, aGc, aPos, des, commandBuffer);
    }

void CHuiCanvasWsPainter::DoHandleBufferStringL(TInt aIndex, TRect& /*aDisplayRect*/, TInt /*aAction*/, const CHuiCanvasVisual& /*aUser*/, CHuiGc* /*aGc*/, TPoint& aPos, TPtr8 aCmds, CHuiCanvasCommandBuffer *aCommandBuffer)
    {
    RMemReadStream& readerStream = iWsCommandBufferReader->Stream();    
    TInt bufLength =  aCmds.Length();
    TPtr8 des = aCmds;
    CHuiCanvasCommandBuffer *commandBuffer = aCommandBuffer;
    TPoint deltaPos = aPos - commandBuffer->iOriginalDisplayRect.iTl;
    
    iCanvasWsGc->SetPositionDelta( deltaPos );
    iWsCommandBufferReader->Init( des, bufLength );
    TInt offset = 0; 
    TInt command = 0;
    do
        {
        command = readerStream.ReadUint8L();
#ifdef HUI_DEBUG_TRACK_DRAWING
        TTlsData::CommandDebugger()->SetDescription( command );
#endif

		// Command cases are ordered approximately in the order so that most common ones are at first
        switch ( command )
            {
            case EAlfFrameContainsUnsupportedCommands:
                {
                TUint8 containsUnsupportedCommands = iWsCommandBufferReader->Stream().ReadUint8L();
                if (containsUnsupportedCommands )
                    {
                    // RDebug::Print(_L("Unsupported commands in this frame"));
                    }
                break;
                }
            case EAlfFrameFlags:
                {
                TInt flags;
                iWsCommandBufferReader->ReadInt32L( flags );
                if ( flags != 0 )
                    {
                    RDebug::Print(_L("FLAGS: %d"), flags );
                    }
                break;
                }
            case EAlfFrameOrientation:
                {
                TInt orientation;
                iWsCommandBufferReader->ReadInt32L( orientation );
                break;
                }

            case EAlfSetUpdateRegion: 
                {
                WsSetUpdateRegionL(aIndex);                    
                break;
                }               
            case EAlfSetShapeRegion: 
                {
                iTempRegion.Clear();                
                iWsCommandBufferReader->ReadRegionL( iTempRegion );
                break;
                }               
            case EAlfSetBrushStyle:
                {
                WsSetBrushStyleL();                  
                break;
                }
            case EAlfSetOrigin:
                {
                WsSetOriginL();
                break;
                }
            case EAlfSetPenStyle:
                {
                WsSetPenStyleL();
                break;
                }
            case EAlfSetClippingRegion:
                {        
                WsSetClippingRegionL();
                break;
                }
            case EAlfResetClippingRegion:
                {
                WsResetClippingRegionL();
                break;
                }
            case EAlfSetBrushColor:
                {
                WsSetBrushColorL();
                break;
                }
            case EAlfBitBltMasked:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsBitBltMaskedL();
                break;
                }
            case EAlfCombinedBitBlitMasked:
				{
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
				WsCombinedBitBlitMaskedL();
				break;
				}
            case EAlfReset:
                {
                WsResetL();
                break;
                }
            case EAlfSetPenColor:
                {
                WsSetPenColorL();
                break;
                }
            case EAlfBitBltRect:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsBitBltRectL();
                break;
                }
            case EAlfSetDrawMode:
                {
                WsSetDrawModeL();
                break;
                }
            case EAlfSetCharJustification:
                {
                WsSetCharJustificationL();
                break;
                }
            case EAlfDrawBitmapMasked:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawBitmapMaskedL();
                break;
                }
            case EAlfSetUnderlineStyle:
                {
                WsSetUnderlineStyleL();
                break;
                }
            case EAlfResetFont:
                {
                WsResetFontL();
                break;
                }
            case EAlfSetStrikethroughStyle:
                {
                WsSetStrikethroughStyleL();
                break;
                }
            case EAlfBitBlt:
              	{
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
              	WsBitBltL();
                break;
              	}
            case EAlfBitBltMaskedPoint:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsBitBltMaskedPointL();
                break;
                }
            case EAlfClear:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsClearL();
                break;
                }
            case EAlfClearRect:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                TRgb transpclearcolor(KRgbWhite);
                transpclearcolor.SetAlpha(0);
                if (iBrushColor == transpclearcolor)
                    {
                    commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsTransparentClear);                    
                    }
                WsClearRectL();
                break;
                }
            case EAlfResetBrushPattern:
                {
                WsResetBrushPatternL();
                break;
                }
            case EAlfDrawText1:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawText1L();
                break;
                }
            case EAlfDrawText2:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawText2L();
                break;
                }
            case EAlfDrawText3:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawText3L();
                break;
                }
            case EAlfDrawText4:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawText4L();
                break;
                }                
            case EAlfDrawText5:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawText5L();
                break;
                 }
            case EAlfDrawArc:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawArcL();
                break;
                }
            case EAlfDrawPie:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawPieL();                    
                break;
                }
            case EAlfDrawBitmap1:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawBitmap1L();                    
                break;
                }
            case EAlfDrawBitmap2:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawBitmap2L();
                break;
                }
            case EAlfDrawBitmap3:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawBitmap3L();
                break;
                }
            case EAlfDrawRoundRect:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawRoundRectL();
                break;
                }
            case EAlfDrawPolyLine:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawPolyLineL();
                break;
                }
            case EAlfDrawPolyLineNoEndPoint:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawPolyLineNoEndPointL();
                break;
                }
            case EAlfDrawPolygon:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawPolygonL();                                     
                break;
                }
            case EAlfDrawEllipse:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawEllipseL();
                break;
                }
            case EAlfDrawLine:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawLineL();
                break;
                }
            case EAlfDrawLineTo:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawLineToL();
                break;
                }
            case EAlfDrawLineBy:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawLineByL();
                break;
                }
            case EAlfDrawRect:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawRectL();
                break;
                }
            case EAlfDrawTextVertical1:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawTextVertical1L();
                break;
                }
            case EAlfDrawTextVertical2:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawTextVertical2L();
                break;
                }                
            case EAlfDrawTextVertical3:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawTextVertical3L();                          
                break;
                } 
            case EAlfDrawTextVertical4: 
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawTextVertical4L();
                break;
                }
            case EAlfDrawTextVertical5:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsDrawTextVertical5L();
                break;
                }
            case EAlfMoveTo:
                {
                WsMoveToL();
                break;
                }
            case EAlfMoveBy:
                {
                WsMoveByL();
                break;
                }
            case EAlfPlot:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsPlotL();
                break;
                }
            case EAlfSetBrushOrigin:
                {
                WsSetBrushOriginL();
                break;
                }
            case EAlfSetPenSize:
                WsSetPenSizeL();                
                break;
            case EAlfSetTextShadowColor:
                {
                WsSetTextShadowColorL();
                break;
                }
            case EAlfSetWordJustification:
                {
                WsSetWordJustificationL();
                break;
                }                
            case EAlfSetBrushPattern:
                {
                WsSetBrushPatternL();
                break;
                }
            case EAlfSetBrushPattern2:
                {
                WsSetBrushPatternL();
                break;
                }
            case EAlfSetFont:
                {
                WsSetFontL();
                break;
                }
            case EAlfContentTag:
                {
                WsContentTagL();
                break;
                }
            case EAlfCopyRect:
                WsCopyRectL();
                break;
            case EAlfUpdateJustification:
                {
                WsUpdateJustificationL();                  
                break;
                }
            case EAlfUpdateJustificationVertical:
                {
                WsUpdateJustificationVerticalL();
                break;
                }
            case EAlfSetFontNoDuplicate:
                {
                WsSetFontNoDuplicateL();
                break;
                }
            case EAlfHasBrushPattern:
            case EAlfHasFont:
            case EAlfBrushColor:
            case EAlfPenColor:
            case EAlfTextShadowColor:
                {
                // these values are cached on client side, we dont do anything.
                break;
                }
            case EAlfCopySettings:
                {
                WsCopySettingsL();                    
                break;    
                }
            case EAlfSetClippingRect:
                {
                WsSetClippingRectL();
                break;
                }
            case EAlfCancelClippingRect:
                {
                WsCancelClippingRectL();
                break;
                }
            case EAlfSetFaded:
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsSetFadedL();
                }
                break;
            case EAlfSetFadingParameters:
                {
                WsSetFadingParametersL();
                break;
                }
            case EAlfFadeArea: 
                {
                commandBuffer->SetStatusFlags(EHuiCanvasBufferContainsDrawing);
                WsFadeAreaL();
                break;
                }
            case EAlfMapColors:
                // MapColors is not supported. Client should never supply this command.
                User::Leave( KErrNotSupported );
                break;
            case EAlfSetUserDisplayMode:
                {
                WsSetUserDisplayModeL();
                break;
                }
            case EAlfUseFont:
                {
                WsUseFontL();                    
                break;
                }
            case EAlfSendSyncDataBlock:
                {
                break;
                }
            case EAlfWindowInactivateWindow:
                {
                // Nothing to do
                break;
                }
            case EAlfPacketPadding:
                {
                DoDigestPaddingL();
				break;
                }
            case EAlfCommandIndexArrayHeader:
                {
                TInt tmp;
                iWsCommandBufferReader->ReadInt8L(); // padding
                iWsCommandBufferReader->ReadInt32L( tmp );
                iWsCommandBufferReader->ReadInt32L( tmp );
                break;
                }
            case EAlfCommandIndexArray:
                {
                TUint8 a = iWsCommandBufferReader->ReadInt8L();
                iWsCommandBufferReader->ReadInt8L();
                iWsCommandBufferReader->ReadInt8L();
                TInt tmp;
                TRect tmp2;
                for(TUint8 i=0;i<a;i++)
                    {
                    iWsCommandBufferReader->ReadInt32L(tmp);
                    iWsCommandBufferReader->ReadInt32L(tmp);
                    iWsCommandBufferReader->ReadInt32L(tmp);
                    iWsCommandBufferReader->ReadRectL(tmp2);
                    }
                break;
                }
              
                
            default:
                {
                // We should never ever get here
                    HUI_DEBUG1(_L("CHuiCanvasVisual::HandleWsBufferL. Error: Unknown command=%d"), command);
                break;
                }
            }// end switch
    		offset = readerStream.Source()->TellL( MStreamBuf::ERead ).Offset();
       	
        } while( offset < bufLength );
#ifdef HUI_DEBUG_TRACK_DRAWING
    TTlsData::CommandDebugger()->EndFrame();
#endif    
    }
    
    
void CHuiCanvasWsPainter::SetCommandSetL( const TDesC8& aCommands )
    {
	CHuiCanvasPainter::SetCommandSetL(aCommands);  

    DoPeekBufferAndUpdateShapeRegionL();
    SelectGcL();
       
    // If shape region has changed recalculate all update regions and remove redundant buffers
    if (iShapeRegionClippingPending)
        {
        ApplyShapeRegion();       
        RemoveRedundantBuffers();   
        }    
    
	// Release currently cached images. 
    // They may still be taken into use after next HandleBuffferL call.
    if (iCanvasVisual)
        {
        iCanvasVisual->Env().CanvasTextureCache().ReleaseAllCachedEntries(*iCanvasVisual);         
        }    
    }
    

void CHuiCanvasWsPainter::ClearCommandSet()
    {
#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
        RDebug::Print(_L(">> CHuiCanvasWsPainter::ClearCommandSet this = %i"), this );
        TTime startTime;
        startTime.UniversalTime();
#endif

    CHuiCanvasPainter::ClearCommandSet();
    
    iShapeRegionAvailable = EFalse;
    
    // Release currently cached images. 
    // They may still be taken into use after next HandleBufferL call.
    if (iCanvasVisual)
        {
        iCanvasVisual->Env().CanvasTextureCache().ReleaseAllCachedEntries(*iCanvasVisual); 
        }

#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
        TTime endTime;
        endTime.UniversalTime();
        TInt timeInMs =  endTime.MicroSecondsFrom( startTime ).Int64()/1000;           
        RDebug::Print(_L(">> CHuiCanvasWsPainter::ClearCommandSet took %i ms"), timeInMs);
#endif
    
    }

struct TArrayHeader
    {
    TInt32 iOffset;
    TInt32 iSize;
    };

void CHuiCanvasWsPainter::AddCommandSetL( const TDesC8& aMoreCommands )
    {    
#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
        RDebug::Print(_L(">> CHuiCanvasWsPainter::AddCommandSetL this = %i"), this );
        TTime startTime;
        startTime.UniversalTime();
#endif

    CHuiCanvasPainter::AddCommandSetL(aMoreCommands);
    DoPeekBufferAndUpdateShapeRegionL();
    SelectGcL();
    
    ApplyShapeRegion();
    
    RemoveRedundantBuffers();   
    
    // New command set may contain BitBlt commands
    // and those cached images must be refreshed
    if (iCanvasVisual)
        {
        // Release currently cached images. 
        // They may still be taken into use after next HandleBufferL call.
        iCanvasVisual->Env().CanvasTextureCache().ReleaseAllCachedEntries(*iCanvasVisual); 
        }

#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
        TTime endTime;
        endTime.UniversalTime();
        TInt timeInMs =  endTime.MicroSecondsFrom( startTime ).Int64()/1000;           
        RDebug::Print(_L(">> CHuiCanvasWsPainter::AddCommandSetL took %i ms"), timeInMs);
#endif

#ifdef HUI_ENABLE_SUBWINDOW_FX        
    TInt count = NumBuffers();
    if (!count) return;
    const TDesC8 &more = At(count-1)->iCommands->Des();
    //RDebug::Print(_L("MoreCommands: %x : %d"), aMoreCommands.Ptr(), aMoreCommands.Length());
    TPtrC8 header = more.Mid(4, sizeof(TArrayHeader)); // the magic comes from CAlfRsSendBuffer::WriteFollowingFrameOffsetL.
    TArrayHeader *ptr = (TArrayHeader*)header.Ptr();
    //RDebug::Print(_L("Ptr: %d : %d"), ptr->iOffset, ptr->iSize);
    TPtrC8 indexTable = more.Mid(ptr->iOffset, ptr->iSize);

    if (iCanvasVisual->Brushes() && iCanvasVisual)
        {
        ParseCmdBufferL(*iCanvasVisual->Brushes(), more, indexTable, CanvasGc(), *CanvasWsGc(), *iCanvasVisual, *this);
        }
#endif
    
#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
        TTime endTime2;
        endTime2.UniversalTime();
        TInt time2InMs =  endTime2.MicroSecondsFrom( startTime ).Int64()/1000;           
        RDebug::Print(_L(">> CHuiCanvasWsPainter::AddCommandSetL including brush creation took %i ms"), time2InMs);
#endif

    }

void CHuiCanvasWsPainter::AddPartialCommandSetL( const TDesC8& aMoreCommands, TBool aLastPart )
    {
    CHuiCanvasPainter::AddPartialCommandSetL(aMoreCommands,aLastPart); 
    }

#ifdef HUI_DEBUG_TRACK_DRAWING
void CHuiCanvasWsPainter::SetTrackCommandSet( TFileName& aFileName, TBool aTrack )
    {
    CHuiCanvasPainter::SetTrackCommandSet( aFileName, aTrack );
    }
#endif

void CHuiCanvasWsPainter::ClearCache()
    {
    if (iCanvasVisual && !iCacheCleared)
        {
#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
        RDebug::Print(_L(">> CHuiCanvasWsPainter::ClearCache this = %i"), this );
        TTime startTime;
        startTime.UniversalTime();
#endif
        TRAP_IGNORE(SelectGcL());
        RenewAllBuffers();         
        SetAllBuffersChanged(ETrue);
        iCanvasWsGc->ClearCache();
        iCanvasVisual->Env().CanvasTextureCache().ReleaseAllCachedEntries(*iCanvasVisual); 
        iCacheCleared = ETrue;
        
#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
        TTime endTime;
        endTime.UniversalTime();
        TInt timeInMs =  endTime.MicroSecondsFrom( startTime ).Int64()/1000;           
        RDebug::Print(_L(">> CHuiCanvasWsPainter::ClearCache took %i ms"), timeInMs);
#endif

        }
    }


void CHuiCanvasWsPainter::WsBitBltL()
    {
    TPoint point(0,0);
    TInt bitmapHandle = 0;
    iWsCommandBufferReader->ReadPointL( point );
    iWsCommandBufferReader->ReadBitmapHandleL( bitmapHandle );
   	iCanvasWsGc->WsBitBltL(bitmapHandle,point);         
    }
    
void CHuiCanvasWsPainter::WsBitBltRectL()
    {
    iWsCommandBufferReader->ReadL( (TUint8*)&iStructBitBlitRect, sizeof( TStructBitBlitRect ) );
    iCanvasWsGc->WsBitBltRectL( 
            iStructBitBlitRect.iBitmapHandle,
            iStructBitBlitRect.iPoint,
            iStructBitBlitRect.iRect);
    }
    
void CHuiCanvasWsPainter::WsBitBltMaskedL()
    {
    iWsCommandBufferReader->ReadL( (TUint8*)&iStructBitBlitMasked, sizeof( TStructBitBlitMasked ) );
	iCanvasWsGc->WsBitBltMaskedL( 
	        iStructBitBlitMasked.iBitmapHandle,
	        iStructBitBlitMasked.iMaskHandle,
	        iStructBitBlitMasked.iInvertMask,
	        iStructBitBlitMasked.iPoint,
	        iStructBitBlitMasked.iRect);         
    }


void  CHuiCanvasWsPainter::WsCombinedBitBlitMaskedL()
	{
	TRect clipRect(0,0,0,0);
	TRect blitRect(0,0,0,0);
	TInt itemCount = iWsCommandBufferReader->ReadInt8L();
	iWsCommandBufferReader->ReadL( (TUint8*)&clipRect, sizeof( TRect ) );
	iWsCommandBufferReader->ReadL( (TUint8*)&blitRect, sizeof( TRect ) );
	    
	TInt index(0);
	
	RArray<THuiCachedCombinedImageParams> combinedBlitItems;
	THuiCachedCombinedImageParams combinedBlitItem;
	while( index++ < itemCount )
		{
		iWsCommandBufferReader->ReadL( (TUint8*)&combinedBlitItem, sizeof( THuiCachedCombinedImageParams ) );
		combinedBlitItems.Append(combinedBlitItem);
		}
	// clipping rects were optimized away by renderstage. it must be set now.
	// We use SetClippingRegion instead of SetClippingRect as they handle ws origin differently.
	iTempRegion.Clear();
    iTempRegion.AddRect(clipRect);
    iCanvasWsGc->WsSetClippingRegionL(iTempRegion);  
	iCanvasWsGc->WsCombinedBitBltMaskedL(blitRect, combinedBlitItems);
    iCanvasWsGc->WsResetClippingRegionL();  
	combinedBlitItems.Close();
	}

void CHuiCanvasWsPainter::WsBitBltMaskedPointL()
    { 
    TPoint point1(0,0);
    TPoint point2(0,0);
    TRect rect(0,0,0,0);
    TInt bitmapHandle = 0;
    TInt maskHandle = 0;
    iWsCommandBufferReader->ReadPointL( point1 );
    iWsCommandBufferReader->ReadBitmapHandleL( bitmapHandle );
    iWsCommandBufferReader->ReadRectL( rect );
    iWsCommandBufferReader->ReadBitmapHandleL( maskHandle );
    iWsCommandBufferReader->ReadPointL( point2 );
    iCanvasWsGc->WsBitBltMaskedPointL(bitmapHandle,maskHandle,point1,point2,rect);
    }
    
void CHuiCanvasWsPainter::WsResetClippingRegionL()
    {    
    iCanvasWsGc->WsResetClippingRegionL();
    }
    
void CHuiCanvasWsPainter::WsClearL()
    {
   	iCanvasWsGc->WsClearL();
    }

void CHuiCanvasWsPainter::WsClearRectL()
    {
    TRect tmpRect1(0,0,0,0);
    iWsCommandBufferReader->ReadRectL( tmpRect1 );
	iCanvasWsGc->WsClearRectL(tmpRect1);
    }

void CHuiCanvasWsPainter::WsResetBrushPatternL()
    {
            
    }

void CHuiCanvasWsPainter::WsResetFontL()
    {    
    iCanvasWsGc->WsResetFontL();
    }

void CHuiCanvasWsPainter::WsDrawArcL()
    {
    TPoint point1(0,0);
    TPoint point2(0,0);
    TRect rect(0,0,0,0);
    iWsCommandBufferReader->ReadRectL( rect );
    iWsCommandBufferReader->ReadPointL( point1 );
    iWsCommandBufferReader->ReadPointL( point2 );
   	iCanvasWsGc->WsDrawArcL(point1,point2,rect);   
    }

void CHuiCanvasWsPainter::WsDrawPieL()
    {
    TPoint point1(0,0);
    TPoint point2(0,0);
    TRect rect(0,0,0,0);
    iWsCommandBufferReader->ReadRectL( rect );
    iWsCommandBufferReader->ReadPointL( point1 );
    iWsCommandBufferReader->ReadPointL( point2 );
    iCanvasWsGc->WsDrawPieL(point1,point2,rect);
    }

void CHuiCanvasWsPainter::WsDrawBitmap1L()
    {
    TRect rect(0,0,0,0);
    TInt bitmapHandle = 0;
    iWsCommandBufferReader->ReadRectL( rect );
    iWsCommandBufferReader->ReadBitmapHandleL( bitmapHandle );
    iCanvasWsGc->WsDrawBitmap1L(bitmapHandle,rect);
    }

void CHuiCanvasWsPainter::WsDrawBitmap2L()
    {
    TRect rect1(0,0,0,0);
    TRect rect2(0,0,0,0);
    TInt bitmapHandle = 0;
    iWsCommandBufferReader->ReadRectL( rect1);
    iWsCommandBufferReader->ReadBitmapHandleL( bitmapHandle );
    iWsCommandBufferReader->ReadRectL( rect2);
    iCanvasWsGc->WsDrawBitmap2L(bitmapHandle,rect1,rect2);
    }

void CHuiCanvasWsPainter::WsDrawBitmap3L()
    {
    TPoint point(0,0);
    TInt bitmapHandle = 0;
    iWsCommandBufferReader->ReadPointL( point );
    iWsCommandBufferReader->ReadBitmapHandleL( bitmapHandle );   
	iCanvasWsGc->WsDrawBitmap3L(bitmapHandle,point);
    }

void CHuiCanvasWsPainter::WsDrawBitmapMaskedL()
    {
    iWsCommandBufferReader->ReadL( (TUint8*)&iStructDrawBitmapMasked, sizeof( TStructDrawBitmapMasked ) );
    iCanvasWsGc->WsDrawBitmapMaskedL(
            iStructDrawBitmapMasked.iBitmapHandle,
            iStructDrawBitmapMasked.iMaskHandle,
            iStructDrawBitmapMasked.iInvertMask,
            iStructDrawBitmapMasked.iRect1,
            iStructDrawBitmapMasked.iRect2);
    }

void CHuiCanvasWsPainter::WsDrawRoundRectL()
    {
    TPoint point(0,0);
    TRect rect(0,0,0,0);        
    iWsCommandBufferReader->ReadRectL( rect );
    iWsCommandBufferReader->ReadPointL( point );    
    iCanvasWsGc->WsDrawRoundRectL(point,rect);    
    }

void CHuiCanvasWsPainter::WsDrawPolyLineL()
    {
    CArrayFix<TPoint>* pointerArray = NULL;    
    iWsCommandBufferReader->ReadPointArrayL( pointerArray );    
    iCanvasWsGc->WsDrawPolyLineL(pointerArray);    
    delete pointerArray;
    }

void CHuiCanvasWsPainter::WsDrawPolyLineNoEndPointL()
    {
    TPoint* pointerArray = NULL;
    TInt count = 0;
    iWsCommandBufferReader->ReadPointArrayL( pointerArray, count );
    iCanvasWsGc->WsDrawPolyLineNoEndPointL(pointerArray,count);
    pointerArray = NULL;
    }

void CHuiCanvasWsPainter::WsDrawPolygonL()
    {
    CArrayFix<TPoint>* pointerArray;
    TInt fillRule = 0;
    iWsCommandBufferReader->ReadPointArrayL( pointerArray );
    iWsCommandBufferReader->ReadInt8L(); // command
    iWsCommandBufferReader->ReadInt32L( fillRule ); 
    iCanvasWsGc->WsDrawPolygonL(pointerArray,fillRule);    
    delete pointerArray;
    }

void CHuiCanvasWsPainter::WsDrawEllipseL()
    {
    TRect rect(0,0,0,0);                        
    iWsCommandBufferReader->ReadRectL( rect );    
    iCanvasWsGc->WsDrawEllipseL(rect);    
    }

void CHuiCanvasWsPainter::WsDrawLineL()
    {
    TPoint start(0,0);
    TPoint end(0,0);
    iWsCommandBufferReader->ReadPointL( start );
    iWsCommandBufferReader->ReadPointL( end );   
    iCanvasWsGc->WsDrawLineL(start,end);    
    }

void CHuiCanvasWsPainter::WsDrawLineToL()
    {
    TPoint point(0,0);
    iWsCommandBufferReader->ReadPointL( point );    
    iCanvasWsGc->WsDrawLineToL(point);    
    }

void CHuiCanvasWsPainter::WsDrawLineByL()
    {
    TPoint point(0,0);
    iWsCommandBufferReader->ReadPointL( point );    
    iCanvasWsGc->WsDrawLineByL(point);    
    }

void CHuiCanvasWsPainter::WsDrawRectL()
    {
    TRect rect(0,0,0,0);                        
    iWsCommandBufferReader->ReadRectL( rect );

	// There is a bug that CScreen::DisplayMode() returns non-alpha display mode (TSW error: ??)
	// That is why WServ clears the window with the color that is opaque (0xFF000400) instead of transparent (0x00000000) 
	#ifdef __ALF_SYMBIAN_RWINDOW_CLEARING_BUG_WORKAROUND__
//	RDebug::Print(_L("HV: CHuiCanvasWsPainter::WsDrawRectL(). iTestBrushColor.Internal()=%x, iTestFullDisplayRect=(%d %d %d %d), rect=(%d %d %d %d) "),
//		iTestBrushColor.Internal(), iTestFullDisplayRect.iTl.iX, iTestFullDisplayRect.iTl.iY,iTestFullDisplayRect.iBr.iX, iTestFullDisplayRect.iBr.iY, 
//		rect.iTl.iX, rect.iTl.iY,rect.iBr.iX, rect.iBr.iY);
	if ( (rect ==  iTestFullDisplayRect) &&  	// Is full screen rect?
	     (iTestBrushColor.Internal() == 0xff000400))  	// Last set color is opaque dark green?
		{
	//	RDebug::Print(_L("HV: CHuiCanvasWsPainter::WsDrawRectL(). Change brush color to 0x00000000. "));
		iCanvasWsGc->WsSetBrushColorL(TRgb(0,0,0,0)); // Replace brush color with transparent black          	  	                            	
		}
	#endif
    
    iCanvasWsGc->WsDrawRectL(rect);    
    }

void CHuiCanvasWsPainter::WsDrawText1L()
    {
    TPtr textValue(0,0);
    TBool success = iWsCommandBufferReader->ReadTextL( textValue, iTextParametersGeneral );
    
    if (textValue.Length() == 0 || !success )
        {
        return;   
        }
    
    iCanvasWsGc->WsDrawText1L(textValue,iTextParametersGeneral);    
    }
    
void CHuiCanvasWsPainter::WsDrawText2L()
    {
    TPoint point(0,0);
    TPtr textValue(0,0);
    TBool success = iWsCommandBufferReader->ReadTextL( textValue, iTextParametersGeneral );
    iWsCommandBufferReader->ReadPointL( point );
    
    if (textValue.Length() == 0 ||!success)
        {
        return;   
        }
	
    iCanvasWsGc->WsDrawText2L(textValue,point,iTextParametersGeneral);    
    }

void CHuiCanvasWsPainter::WsDrawText3L()
    {
    TRect rect(0,0,0,0);
    TPtr textValue(0,0);
    TBool success = iWsCommandBufferReader->ReadTextL( textValue, iTextParametersGeneral );
    iWsCommandBufferReader->ReadRectL( rect );

    if (textValue.Length() == 0 || !success )
        {
        return;   
        }
	
    iCanvasWsGc->WsDrawText3L(textValue,rect,iTextParametersGeneral);    
    }

void CHuiCanvasWsPainter::WsDrawText4L()
    {
    TPtr textValue(0,0);
    TBool success = iWsCommandBufferReader->ReadTextL( textValue, iTextParametersGeneral );
    iWsCommandBufferReader->ReadL( (TUint8*)&iStructDrawTextGeneral, sizeof( TStructDrawTextGeneral ) - sizeof(TInt) );
    
    if (textValue.Length() == 0 || !success )
            {
            return;   
            }

    iCanvasWsGc->WsDrawText4L(textValue,
            iStructDrawTextGeneral.iRect,
            iStructDrawTextGeneral.iValue1,  // textBaselineOffset
            iStructDrawTextGeneral.iValue2, // textAlign
            iStructDrawTextGeneral.iValue3, // textMargin,
            iTextParametersGeneral);    
    }

void CHuiCanvasWsPainter::WsDrawText5L()
    {
    TPtr textValue(0,0);
    TBool success = iWsCommandBufferReader->ReadTextL( textValue, iTextParametersGeneral );
    iWsCommandBufferReader->ReadL( (TUint8*)&iStructDrawTextGeneral, sizeof( TStructDrawTextGeneral ) );
    
    if (textValue.Length() == 0 || !success )
        {
        return;   
        }

	iCanvasWsGc->WsDrawText5L(textValue,
	        iStructDrawTextGeneral.iRect,
	        iStructDrawTextGeneral.iValue1,  // textBaselineOffset
	        iStructDrawTextGeneral.iValue3, // textAlign
	        iStructDrawTextGeneral.iValue4, // textMargin,
	        iStructDrawTextGeneral.iValue2, // textWidth
	        iTextParametersGeneral);    
    }

void CHuiCanvasWsPainter::WsDrawTextVertical1L()
    {
    TInt textUp = 0;
    TPtr textValue(0,0);
    TBool success = iWsCommandBufferReader->ReadTextL( textValue, iTextParametersGeneral );
    iWsCommandBufferReader->ReadInt32L( textUp );  
    
    if (textValue.Length() == 0 || !success )
        {
        return;   
        }

	iCanvasWsGc->WsDrawTextVertical1L(textValue,textUp,iTextParametersGeneral);    
    }

void CHuiCanvasWsPainter::WsDrawTextVertical2L()
    {
    TPoint point(0,0);
    TInt textUp = 0;
    TPtr textValue(0,0);
    TBool success = iWsCommandBufferReader->ReadTextL( textValue, iTextParametersGeneral );
    iWsCommandBufferReader->ReadPointL( point );
    iWsCommandBufferReader->ReadInt32L( textUp );  

    if (textValue.Length() == 0 || !success )
            {
            return;   
            }
        
	iCanvasWsGc->WsDrawTextVertical2L(textValue,textUp,point,iTextParametersGeneral);    
    }


void CHuiCanvasWsPainter::WsDrawTextVertical3L()
    {
    TRect rect(0,0,0,0);
    TInt textUp = 0;
    TPtr textValue(0,0);
    TBool success = iWsCommandBufferReader->ReadTextL( textValue, iTextParametersGeneral);
    iWsCommandBufferReader->ReadRectL( rect );
    iWsCommandBufferReader->ReadInt32L( textUp ); 

    if (textValue.Length() == 0 || !success )
            {
            return;   
            }
    
    iCanvasWsGc->WsDrawTextVertical3L(textValue,textUp,rect,iTextParametersGeneral);    
    }

void CHuiCanvasWsPainter::WsDrawTextVertical4L()
    {
    TRect rect(0,0,0,0);
    TInt textBaselineOffset = 0;
    TInt textUp = 0;
    TInt textAlign = 0;
    TInt textMargin = 0;
    TPtr textValue(0,0);
    
    TBool success = iWsCommandBufferReader->ReadTextL( textValue, iTextParametersGeneral );
    iWsCommandBufferReader->ReadRectL( rect );
    iWsCommandBufferReader->ReadInt32L( textBaselineOffset );
    iWsCommandBufferReader->ReadInt32L( textUp );
    iWsCommandBufferReader->ReadInt32L( textAlign );
    iWsCommandBufferReader->ReadInt32L( textMargin );

    if (textValue.Length() == 0 || !success )
            {
            return;   
            }

    iCanvasWsGc->WsDrawTextVertical4L(textValue,rect,textBaselineOffset,textUp,textAlign,textMargin,iTextParametersGeneral);    
    }

void CHuiCanvasWsPainter::WsDrawTextVertical5L()
    {
    TRect rect(0,0,0,0);
    TInt textBaselineOffset = 0;
    TInt textWidth = 0;
    TInt textUp = 0;
    TInt textAlign = 0;
    TInt textMargin = 0;
    TPtr textValue(0,0);
    
    iWsCommandBufferReader->ReadTextL( textValue, iTextParametersGeneral );
    iWsCommandBufferReader->ReadRectL( rect );
    iWsCommandBufferReader->ReadInt32L( textBaselineOffset );
    iWsCommandBufferReader->ReadInt32L( textWidth );
    iWsCommandBufferReader->ReadInt32L( textUp );
    iWsCommandBufferReader->ReadInt32L( textAlign );
    iWsCommandBufferReader->ReadInt32L( textMargin );

    if (textValue.Length() == 0)
            {
            return;   
            }

    iCanvasWsGc->WsDrawTextVertical5L(textValue,rect,textBaselineOffset,textUp,textAlign,textMargin,textWidth,iTextParametersGeneral);    
    }

void CHuiCanvasWsPainter::WsMoveToL()
    {
    TPoint point(0,0);        
    iWsCommandBufferReader->ReadPointL( point );
    iCanvasWsGc->WsMoveToL(point);
    }

void CHuiCanvasWsPainter::WsMoveByL()
    {
    TPoint point(0,0);        
    iWsCommandBufferReader->ReadPointL( point );    
    iCanvasWsGc->WsMoveByL(point);
    }

void CHuiCanvasWsPainter::WsPlotL()
    {
    TPoint point(0,0);        
    iWsCommandBufferReader->ReadPointL( point );    
    iCanvasWsGc->WsPlotL(point);               	  	                        
    }

void CHuiCanvasWsPainter::WsResetL()
    {
    iCanvasWsGc->WsResetL();               	  	                            

	#ifdef __ALF_SYMBIAN_RWINDOW_CLEARING_BUG_WORKAROUND__
	iTestBrushColor.SetInternal(0);
	#endif	
	iBrushColor.SetInternal(0);
    }

void CHuiCanvasWsPainter::WsSetBrushColorL()
    {
    TRgb color = 0;        
    iWsCommandBufferReader->ReadColorL( color );
	iCanvasWsGc->WsSetBrushColorL(color);           	  	                            

	#ifdef __ALF_SYMBIAN_RWINDOW_CLEARING_BUG_WORKAROUND__
	iTestBrushColor = color;    	  	                            	
	#endif
	iBrushColor = color;
    }

void CHuiCanvasWsPainter::WsSetBrushOriginL()
    {
    TPoint point(0,0);        
    iWsCommandBufferReader->ReadPointL( point );
	iCanvasWsGc->WsSetBrushOriginL(point);	
    }

void CHuiCanvasWsPainter::WsSetBrushStyleL()
    {
    TInt style = 0;
    iWsCommandBufferReader->ReadInt32L( style );
	iCanvasWsGc->WsSetBrushStyleL(style);        
    }

void CHuiCanvasWsPainter::WsSetClippingRegionL()
    {
    iTempRegion.Clear();
    iWsCommandBufferReader->ReadRegionL( iTempRegion );
    iCanvasWsGc->WsSetClippingRegionL(iTempRegion);
    }

void CHuiCanvasWsPainter::WsSetDrawModeL()
    {
    TInt drawMode = 0;    
    iWsCommandBufferReader->ReadInt32L( drawMode );
	iCanvasWsGc->WsSetDrawModeL(drawMode);
    }

void CHuiCanvasWsPainter::WsSetOriginL()
    {
    TPoint origin(0,0);        
    iWsCommandBufferReader->ReadPointL(origin);
   	iCanvasWsGc->WsSetOriginL(origin);
    }

void CHuiCanvasWsPainter::WsSetPenColorL()
    {
    TRgb color = 0;        
    iWsCommandBufferReader->ReadColorL( color );
	iCanvasWsGc->WsSetPenColorL(color);    
    }

void CHuiCanvasWsPainter::WsSetPenStyleL()
    {
    TInt style = 0;    
    iWsCommandBufferReader->ReadInt32L( style );
	iCanvasWsGc->WsSetPenStyleL(style);
    }

void CHuiCanvasWsPainter::WsSetPenSizeL()
    {
    TInt width = 0;    
    TInt height = 0;    
    iWsCommandBufferReader->ReadInt32L( width ); 
    iWsCommandBufferReader->ReadInt32L( height ); 
    iCanvasWsGc->WsSetPenSizeL(width,height);
    //\todo: Separate pen width and height are not yet supported 	
    }

void CHuiCanvasWsPainter::WsSetTextShadowColorL()
    {
    TRgb color = 0;        
    iWsCommandBufferReader->ReadColorL( color );
    iCanvasWsGc->WsSetTextShadowColorL(color);
    }

void CHuiCanvasWsPainter::WsSetCharJustificationL()
    {
    TInt excessWidth = 0;
    TInt numGaps = 0;
    iWsCommandBufferReader->ReadInt32L( excessWidth );
    iWsCommandBufferReader->ReadInt32L( numGaps ); // NumChars
	iCanvasWsGc->WsSetCharJustificationL(excessWidth,numGaps);
    }

void CHuiCanvasWsPainter::WsSetWordJustificationL()
    {
    TInt excessWidth = 0;
    TInt numGaps = 0;
    iWsCommandBufferReader->ReadInt32L( excessWidth );
    iWsCommandBufferReader->ReadInt32L( numGaps ); // NumChars
	iCanvasWsGc->WsSetWordJustificationL(excessWidth,numGaps);        
    }

void CHuiCanvasWsPainter::WsSetUnderlineStyleL()
    {
    TInt value = 0;
    iWsCommandBufferReader->ReadInt32L( value );
    iCanvasWsGc->WsSetUnderlineStyleL(value);
    }

void CHuiCanvasWsPainter::WsSetStrikethroughStyleL()
    {
    TInt value = 0;
    iWsCommandBufferReader->ReadInt32L( value );
    // todo: is this magic 1000 safe offset?
    iCanvasWsGc->WsSetUnderlineStyleL(value+1000);
    }


void CHuiCanvasWsPainter::WsSetBrushPatternL()
    {
    TInt value = 0;        
    iWsCommandBufferReader->ReadInt32L( value );
	iCanvasWsGc->WsSetBrushPatternL(value);
    }

void CHuiCanvasWsPainter::WsSetFontL()
    {
    TInt fontId = 0;
    iWsCommandBufferReader->ReadInt32L( fontId );// Font type Uid
    iCanvasWsGc->WsSetFontL(fontId);    
    }

void CHuiCanvasWsPainter::WsContentTagL()
    {
    TInt tag;
    iWsCommandBufferReader->ReadInt32L( tag );
    }

void CHuiCanvasWsPainter::WsCopyRectL()
    {
    TPoint point(0,0);
    TRect rect(0,0,0,0);
    iWsCommandBufferReader->ReadPointL( point );
    iWsCommandBufferReader->ReadRectL( rect );
	iCanvasWsGc->WsCopyRectL(point,rect);
    }

void CHuiCanvasWsPainter::WsUpdateJustificationL()
    {
    TPtr textValue(0,0);
    iWsCommandBufferReader->ReadTextL( textValue, iTextParametersGeneral );	
	iCanvasWsGc->WsUpdateJustificationL(textValue);
    }

void CHuiCanvasWsPainter::WsUpdateJustificationVerticalL()
    {
    TPtr textValue(0,0);
    TInt value = 0;

    iWsCommandBufferReader->ReadTextL( textValue, iTextParametersGeneral );
    iWsCommandBufferReader->ReadInt32L( value );
	iCanvasWsGc->WsUpdateJustificationVerticalL(value,textValue);
   }

void CHuiCanvasWsPainter::WsSetFontNoDuplicateL()
    {
    TInt tempFont = 0;
    iWsCommandBufferReader->ReadInt32L( tempFont );
	iCanvasWsGc->WsSetFontNoDuplicateL(tempFont);	    
    }


void CHuiCanvasWsPainter::WsCopySettingsL()
    {
    iCanvasWsGc->WsCopySettingsL();	
    }

void CHuiCanvasWsPainter::WsSetClippingRectL()
    {
    TRect rect(0,0,0,0);
    iWsCommandBufferReader->ReadRectL( rect );
	iCanvasWsGc->WsSetClippingRectL(rect);	                        
    }

void CHuiCanvasWsPainter::WsCancelClippingRectL()
    {
    iCanvasWsGc->WsCancelClippingRectL();
    }

void CHuiCanvasWsPainter::WsSetFadedL()
    {
    TInt faded = 0;
    iWsCommandBufferReader->ReadInt32L( faded );
	iCanvasWsGc->WsSetFadedL(faded);	                        
    }

void CHuiCanvasWsPainter::WsSetFadingParametersL()
    {
    TInt blackMap = 0;        
    TInt whiteMap = 0;        
    iWsCommandBufferReader->ReadInt32L( blackMap );
    iWsCommandBufferReader->ReadInt32L( whiteMap );
	iCanvasWsGc->WsSetFadingParametersL(blackMap,whiteMap);	                        
    }

void CHuiCanvasWsPainter::WsFadeAreaL()
    {
    iTempRegion.Clear();
    iWsCommandBufferReader->ReadRegionL( iTempRegion );    
	iCanvasWsGc->WsFadeAreaL(iTempRegion);	                        
    }

void CHuiCanvasWsPainter::WsMapColorsL()
    {
    iCanvasWsGc->WsMapColorsL();	                        
    }

void CHuiCanvasWsPainter::WsSetUserDisplayModeL()
    {
    TInt mode = 0;
    iWsCommandBufferReader->ReadInt32L( mode );
	iCanvasWsGc->WsSetUserDisplayModeL(mode);	                        
        
    }

void CHuiCanvasWsPainter::WsUseFontL()
    {
	TInt tempFont = 0;
    iWsCommandBufferReader->ReadInt32L( tempFont );
    iCanvasWsGc->WsUseFontL(tempFont);	                                
    }       

void CHuiCanvasWsPainter::WsSetUpdateRegionL(TInt aIndex)
    {
    iTempRegion.Clear();                
    iWsCommandBufferReader->ReadRegionL( iTempRegion );
    if (aIndex==-1) return; //TP
    // Update region is modified when new buffers are added after this buffer, 
    // so store the region only at first read. 
    if (iCommandBuffers[aIndex]->iChanged && iCommandBuffers[aIndex]->iOriginalUpdateRegion.Count() == 0)
        {
        // Check first that the coordiates are not insane (sometimes thay are)
        TInt count = iTempRegion.Count();                    
        TRect displayRect = iCanvasVisual->DisplayRect();
        for (TInt i=count-1; i>=0; i--)
            {
            TRect rect = iTempRegion[i];

            // - Sometimes updateregion is outiside window (WSERV...why?!) 
            //   We clip it here to avoid ui probs.
            // - Lets remove this for now, this seems to break scrollbars again
            //   when window parent-child relations work..
            // - Hmm, should we add this anyway because now the idle softkeys are lost again in landscape mode ?
            // - Added again after WSERV fix in the window parent-child relations
            // - Rect may be outside the screen and that's fine (Visual may be moved later).
#ifndef HUI_DISABLE_CANVAS_VISUAL_CLIPPING
            rect.Intersection(displayRect); 
#endif                
            iCommandBuffers[aIndex]->iUpdateRegion.AddRect(rect);    
            iCommandBuffers[aIndex]->iOriginalUpdateRegion.AddRect(rect);    
            }                
        
        // Combine areas that are next to each others
        iCommandBuffers[aIndex]->iUpdateRegion.Tidy();                    
        iCommandBuffers[aIndex]->iOriginalUpdateRegion.Tidy();                    

        // Subtract this buffers update area from previous buffers update areas to avoid overdraw

 // TODO: Subtraction is for now commented out because it seems to cause UI problems, especially
 //       with lists with scrollbar. Try e.g. opening image from filebrowser, then press back and
 //       scrollbar area is often corrupted. This happens (probaply) because first command buffer contains
 //       real background drawing under scrollbar, but partial command buffers do not contain it although 
 //       their update region extends below scrollbar.
 //       
 //       This issue should be fixed because leaving subration undone causes performance to be worse.
 //       
        
 /*
        if (aIndex > 0)
            {
            for (TInt i=aIndex; i>0; i--)
                {
                TInt previous = aIndex - 1;
                iCommandBuffers[previous]->iUpdateRegion.SubRegion(iCommandBuffers[aIndex]->iUpdateRegion);
                iCommandBuffers[previous]->iUpdateRegion.Tidy();                            
                }            
            }
*/            
        }
    }

void CHuiCanvasWsPainter::WsSetShapeRegionL( TInt aIndex )
    {
    iTempRegion.Clear();                
    iWsCommandBufferReader->ReadRegionL( iTempRegion );
    
	
    // If there is a shape region, get it only from the newest buffer. 
    // This is the case when the buffer has just been added to the canvas visual.
    
    if(aIndex == iCommandBuffers.Count() - 1)
        {
        // Note: The "set shape" command looks to be used only if it really is different from
        // the window rect. So there is no need to check if the shape region is relevant. 
        iShapeRegion.Copy(iTempRegion);

        // note: iUpdateRegion will be updated later, set flags to indicate pending
        iShapeRegionAvailable = ETrue;
        iShapeRegionOrigin = iCanvasVisual->DisplayRect().Round().iTl;
        
        iShapeRegionClearingPending = ETrue;
        iShapeRegionClippingPending = ETrue;
        }
    
	
    #ifdef _DEBUG
    if (iShapeRegion.Count() == 0 && iTempRegion.Count() > 0)
        {
        HUI_DEBUG(_L("CHuiCanvasWsPainter::WsSetShapeRegionL. Error: iShapeRegion not set by any command buffer! However, there exists at least one command buffer that has shape region command."));
        }
    #endif
    }

void CHuiCanvasWsPainter::DoDigestPaddingL()
    {
    TUint8 padding = iWsCommandBufferReader->ReadInt8L();
    while( padding-- )
        {
#ifdef _DEBUG
        if ( iWsCommandBufferReader->ReadInt8L() != 0 )
            {
            RDebug::Print(_L("CHuiCanvasWsPainter::DigestPaddingL - Padding error"));
            USER_INVARIANT();
            }
#else
        iWsCommandBufferReader->ReadInt8L();
#endif        
        }
    }

void CHuiCanvasWsPainter::DestroyBuffer(TInt aIndex)
    {
    CHuiCanvasCommandBuffer* buffer = iCommandBuffers[aIndex];

    TTime now;
    now.UniversalTime();    
    TInt lifetimeInMs =  now.MicroSecondsFrom( buffer->iCreationTime ).Int64()/1000;                               
    if (lifetimeInMs > 0 && lifetimeInMs < KHuiCanvasDisableRenderBufferHandleInterval)
        {
        /* Check and disable render buffer if needed */
        if (iCommandBuffers.Count() == 2)
            {
            EnableRenderBufferIfNeeded(EFalse);
            }
        }
    
    iCommandBuffers.Remove(aIndex);
    delete buffer;
    }


TBool CHuiCanvasWsPainter::RemoveRedundantBuffers()
    {
    TBool didRemoveBuffers = EFalse;
    TInt originalBufferCount = iCommandBuffers.Count();
    
    RemoveBuffersWithoutRealDrawing();

    // Don't remove command buffers with modified display rect.
	// Instead, apply clipping.
    //RemoveBuffersWithMovedDisplayRect();
    ModifyBuffersWithChangedDisplayRect();
    //RemoveBuffersWithOldDisplayRect();
    
    RemoveBuffersWithEmptyUpdateRegion();
    RemoveBuffersWithOverlappingUpdateRegion();         
    
    didRemoveBuffers = (originalBufferCount != iCommandBuffers.Count());    
    return didRemoveBuffers;
    }

void CHuiCanvasWsPainter::RemoveBuffersWithMovedDisplayRect()
    {
    TInt bufferCount = iCommandBuffers.Count();
    
    TRect canvas = iCanvasVisual->DisplayRect().Round();
    for (TInt cb = bufferCount - 1; cb >= 0; cb--)
        {
        CHuiCanvasCommandBuffer* buffer = iCommandBuffers[cb];
        TRect bufRect = buffer->iOriginalDisplayRect.Round();
        
        // If the visual has moved, delete the old buffer
        if (bufRect.iTl != canvas.iTl)
            {
            DestroyBuffer(cb);
            }
        }
    }

void CHuiCanvasWsPainter::ModifyBuffersWithChangedDisplayRect()
    {
    TInt bufferCount = iCommandBuffers.Count();
    TRect canvasRect = iCanvasVisual->DisplayRect().Round();
    TRegionFix<1> region(canvasRect);

    // We must first offset to canvasRect.iTl, otherwise region clipping doesn't work.
    UpdateBufferUpdateRegions(canvasRect.iTl);
    
    // If the buffers have different update region than CanvasVisual, clip
    // the drawing to canvas visual's & cmdbuffer's updateregions' intersection.
    for (TInt cb = 0; cb < bufferCount; cb++)
        {
        CHuiCanvasCommandBuffer* cmdbuffer = iCommandBuffers[cb];
        TRect bufRect = cmdbuffer->iOriginalDisplayRect.Round();
                
        if (bufRect != canvasRect)
            {
            cmdbuffer->iUpdateRegion.Copy(cmdbuffer->iOriginalUpdateRegion);
            
            TPoint deltaPos = cmdbuffer->iPositionForUpdateRegion - cmdbuffer->iOriginalDisplayRect.Round().iTl;
            cmdbuffer->iUpdateRegion.Offset(deltaPos);
            
            cmdbuffer->iUpdateRegion.Intersect(region);
            
            if ( iShapeRegionAvailable )
                {
                TranslateShapeRegion(cmdbuffer->iPositionForUpdateRegion);
                cmdbuffer->iUpdateRegion.Intersect(iShapeRegion);
                }
            
            cmdbuffer->iUpdateRegion.Tidy();
            }
        }
    }

void CHuiCanvasWsPainter::RemoveBuffersWithoutRealDrawing()
    {
    TInt bufferCount = iCommandBuffers.Count();
    for (TInt cb = bufferCount - 1; cb >= 0; cb--)
        {
        CHuiCanvasCommandBuffer* buffer = iCommandBuffers[cb];
        TInt flags = buffer->iStatusFlags;
        if ((flags & EHuiCanvasBufferStatusScanned) && !(flags & EHuiCanvasBufferContainsDrawing))
            {
            DestroyBuffer(cb);
            }
        }        
    }


void CHuiCanvasWsPainter::RemoveBuffersWithOldDisplayRect() 
    {
    TInt bufferCount = iCommandBuffers.Count();
    for (TInt cb = bufferCount - 1; cb >= 0; cb--)
        {
        CHuiCanvasCommandBuffer* buffer = iCommandBuffers[cb];
        if (buffer->iOriginalDisplayRect.Round() != iCanvasVisual->DisplayRect().Round())
            {
            DestroyBuffer(cb);
            }
        }    
    }

void CHuiCanvasWsPainter::RemoveBuffersWithEmptyUpdateRegion() 
    {
    TInt bufferCount = iCommandBuffers.Count();
    for (TInt cb = bufferCount - 1; cb >= 0; cb--)
        {
        CHuiCanvasCommandBuffer* buffer = iCommandBuffers[cb];
        if (buffer->iOriginalUpdateRegion.Count() == 0)
            {        
            DestroyBuffer(cb);
            }
        }    
    }

void CHuiCanvasWsPainter::RemoveBuffersWithOverlappingUpdateRegion() 
    {
    // Check possibly overlapping update regions
    TBool arraysChanged = ETrue;  
    while (arraysChanged)
        {
        arraysChanged = EFalse;
        iTempRegion.Clear();
        
        // Loop all buffers                
        TInt bufferCount = iCommandBuffers.Count();        
        for (TInt cb = bufferCount - 1; cb >= 0; cb--)
            {            
            if (arraysChanged)
                {
                break;    
                }
            
            CHuiCanvasCommandBuffer* cmdbuffer = iCommandBuffers[cb];
            // Translate region to be relative to visual top left corner.
            TPoint offset = -cmdbuffer->iOriginalDisplayRect.Round().iTl;

            for (TInt j=0; j < cmdbuffer->iOriginalUpdateRegion.Count();j++)
                {
                TRect rect = cmdbuffer->iOriginalUpdateRegion[j];
                rect.Move(offset);
                iTempRegion.AddRect(rect);
                }
                        
            // Check older buffers for overlapping regions against current buffer
            if (cb > 0)
                {                   
                for (TInt i = cb - 1; i >= 0; i--)
                    {
                    if (arraysChanged)
                        {
                        break;    
                        }

                    CHuiCanvasCommandBuffer* previousCommands = iCommandBuffers[i];
                    TPoint previousCommandsOffset = previousCommands->iOriginalDisplayRect.Round().iTl;
                    
                    // Keep count how many subregions of the prevous command are contained inside current command buffer region
                    TInt coveredRegionCount = 0;                    
                    for (TInt k=0; k < previousCommands->iOriginalUpdateRegion.Count();k++)
                        {
                        iTempCurrentSubRegion.Clear();
                        iTempIntersectingRegion.Clear();                                               
                        iTempCurrentSubRegion.AddRect(previousCommands->iOriginalUpdateRegion[k]);
                                                
                        iTempCurrentSubRegion.Offset(-previousCommandsOffset);
                        
                        iTempIntersectingRegion.Intersection(iTempRegion, iTempCurrentSubRegion);
                        iTempIntersectingRegion.Tidy();
                        
                        if (iTempIntersectingRegion.Count() == 1)
                            {
                            iTempIntersectingRegion.Offset(previousCommandsOffset);
                        
                            if (iTempIntersectingRegion[0] == previousCommands->iOriginalUpdateRegion[k])
                                {
                                coveredRegionCount++;
                                // If all regions were overlapping agains current buffer, we can delete this.
                                if (coveredRegionCount == previousCommands->iOriginalUpdateRegion.Count())
                                    {
                                    DestroyBuffer(i);
                                    arraysChanged = ETrue;
                                    break;                                                                            
                                    }
                                }
                            else
                                {
                                // There is no reason to continue with this one if even one of its subregions
                                // is  outside overlapping region.
                                break;                                    
                                }
                            }                        
                        }
                    }
                }
            }
        }
    }

void CHuiCanvasWsPainter::ApplyShapeRegion()
    {
    // If shape region has changed recalculate all update regions
    if (iShapeRegionClippingPending)
        {
        TRect canvasRect = iCanvasVisual->DisplayRect().Round();

        // We must first offset to canvasRect.iTl, otherwise region clipping doesn't work.
        UpdateBufferUpdateRegions(canvasRect.iTl);

        TInt bufferCount = iCommandBuffers.Count();
        for (TInt cb = 0; cb < bufferCount; cb++)
            {        
            CHuiCanvasCommandBuffer* cmdbuffer = iCommandBuffers[cb];
            cmdbuffer->iUpdateRegion.Copy(cmdbuffer->iOriginalUpdateRegion);                

            TPoint deltaPos = cmdbuffer->iPositionForUpdateRegion - cmdbuffer->iOriginalDisplayRect.Round().iTl;
            cmdbuffer->iUpdateRegion.Offset(deltaPos);

            if ( iShapeRegionAvailable )
                {
                TranslateShapeRegion(cmdbuffer->iPositionForUpdateRegion);                 
                cmdbuffer->iUpdateRegion.Intersect(iShapeRegion);
                }
            cmdbuffer->iUpdateRegion.Tidy();
            }
        iShapeRegionClippingPending = EFalse;       
        }    
    }
    
void CHuiCanvasWsPainter::TranslateShapeRegion(const TPoint& aNewOrigin)
    {
    if (iShapeRegionOrigin != aNewOrigin)
        {
        iShapeRegion.Offset(aNewOrigin - iShapeRegionOrigin);
        iShapeRegionOrigin = aNewOrigin;
        }
    }

CHuiCanvasGc& CHuiCanvasWsPainter::CanvasGc() const
	{
	return iCanvasWsGc->CanvasGc();
	}

TInt CHuiCanvasWsPainter::PaintedAreaCount() const
    {
    TInt paintedAreaCount = 0;
    TInt bufferCount = iCommandBuffers.Count();
    for (TInt cb = 0; cb < bufferCount; cb++)
        {        
        paintedAreaCount += iCommandBuffers[cb]->iUpdateRegion.Count();
        }
    return paintedAreaCount;
    }
    
THuiCanvasPaintedArea CHuiCanvasWsPainter::PaintedArea(TInt aIndex)
    {
    THuiCanvasPaintedArea area;
    area.iPaintType = EHuiCanvasPaintTypeOpaque;
    area.iFlags = 0;    
    
    TInt firstIndexInCurrentBuffer = 0;
    TInt lastIndexInCurrentBuffer = 0;
    TInt indexCounter = 0;
    
    TInt bufferCount = iCommandBuffers.Count();
    for (TInt cb = 0; cb < bufferCount; cb++)
        {
        TInt updateRegionCount = iCommandBuffers[cb]->iUpdateRegion.Count();
        if (updateRegionCount)
            {        
            firstIndexInCurrentBuffer = indexCounter;
            lastIndexInCurrentBuffer = firstIndexInCurrentBuffer + updateRegionCount - 1;
            
            if ((firstIndexInCurrentBuffer <= aIndex) && (aIndex <= lastIndexInCurrentBuffer))
                {
                TInt localIndex = aIndex - firstIndexInCurrentBuffer;
                area.iPaintedRect = iCommandBuffers[cb]->iUpdateRegion[localIndex];
                break;
                }        
            indexCounter += updateRegionCount;        
            }
       }   
    return area;
    }

TInt CHuiCanvasWsPainter::SetCapturingBufferL(CFbsBitmap* aTarget)
    {
    TInt result = iCanvasWsGc->SetCapturingBufferL(aTarget);
        
    if ( !aTarget )
        {
        // We may have switched to another GC - so to ensure that 
        // all are released, we will send this request to all.
        CHuiCanvasWsGc* gcs[] = 
            { 
            iCanvasWsBitGc, 
            iCanvasWsSwGc, 
            iCanvasWsHwGc 
            };
        TInt count = sizeof(gcs) / sizeof(CHuiCanvasWsGc*);
        for ( TInt i = count - 1; i >= 0; --i )
            {
            if ( gcs[i] && gcs[i] != iCanvasWsGc )
                {
                gcs[i]->SetCapturingBufferL(NULL);
                }
            }
        }

    return result;
    }

void CHuiCanvasWsPainter::ClearCapturingBufferArea(const TRect& aRect)
    {
    iCanvasWsGc->ClearCapturingBufferArea(aRect);
    }

TRect CHuiCanvasWsPainter::DirtyRect() const
    {
    iTempRegion.Clear();                
    TInt bufferCount = iCommandBuffers.Count();
    for (TInt cb = 0; cb < bufferCount; cb++)
        {        
        const CHuiCanvasCommandBuffer& cmdbuffer = *iCommandBuffers[cb];
        
        // Report only changed buffers. This should be ok as long as
        // this method is only used when scanning visual tree and
        // thus visual (and buffer) changed flags are in correct states.
        if (cmdbuffer.iChanged)
            {
            iTempRegion.Union(cmdbuffer.iUpdateRegion);
            }
        }
    return iTempRegion.BoundingRect();
    }

TBool CHuiCanvasWsPainter::IsBufferCompletelyOutisideClippingRegion(const CHuiCanvasCommandBuffer& aCommandbuffer) const
    {
    CHuiGc* gc = iCanvasWsGc->CanvasGc().Gc();
    if (gc && gc->ClipRegion().Count())
        {
        // This is a bit tricky part, gc clipregion is in transformed coordinates but our update region is not.
        // So we must transform our update region before we can compare it to gc clipping region and
        // know if it falls comletely outside it or not.        
        iTempRegion.Clear();
        for (TInt i=0; i<aCommandbuffer.iUpdateRegion.Count();i++)
            {
            THuiRealRect transformed = aCommandbuffer.iUpdateRegion[i];
            gc->TransformDirtyRect(transformed);
            iTempRegion.AddRect(transformed.Round());            
            }
        
        CHuiCanvasGc::TClipRectVisibility visibility = iCanvasWsGc->CanvasGc().IsClipped(iTempRegion, gc->ClipRegion());
        
        if (visibility == CHuiCanvasGc::EFullyOutside)
            {
            return ETrue;
            }
        }

    return EFalse;
    }

TInt CHuiCanvasWsPainter::EnableRenderBuffer(TBool aEnable)
    {
    iEnableRenderBuffer = aEnable;
    
    if (iCanvasWsGc && ( aEnable != iCanvasWsGc->IsRenderBufferEnabled() ) )
        {
        if (aEnable)
            {
            // Must redraw all buffers to render buffer at next frame
            RenewAllBuffers();         
            }        
        return iCanvasWsGc->EnableRenderbuffer(aEnable);
        }
    else
        {
        return KErrNone;
        }    
    }

void CHuiCanvasWsPainter::EnableRenderBufferIfNeeded(TBool aEnable)
    {
    if (!KHuiCanvasAutomaticRenderBufferUsage || !CHuiStatic::Renderer().Allows(EHuiRenderPluginAllowVisualPBufferSurfaces))
        {
        return;
        }
    
    if (aEnable)
        {
        if (iAutomaticRenderBufferUsage && !iCanvasWsGc->IsRenderBufferEnabled() && HasOldCommandBuffers(KHuiCanvasEnableRenderBufferHandleInterval))
            {
            RDebug::Print(_L("CHuiCanvasWsPainter::EnableRenderBufferIfNeeded: Enabling renderbuffer"));
            EnableRenderBuffer(ETrue);
            iAutomaticRenderBufferUsage = ETrue;
            }        
        }
    else
        {
        if (iCanvasWsGc->IsRenderBufferEnabled())
            {
            RDebug::Print(_L("CHuiCanvasWsPainter::EnableRenderBufferIfNeeded: Disabling renderbuffer"));
            EnableRenderBuffer(EFalse);
            iAutomaticRenderBufferUsage = ETrue;
            }
        }    
    }

void CHuiCanvasWsPainter::SelectGcL()
    {
    TBool hasUnsupportedCommands = EFalse;
    TInt bufferCount = iCommandBuffers.Count();
    for (TInt cb = 0; cb < bufferCount; cb++)
        {        
        const CHuiCanvasCommandBuffer& cmdbuffer = *iCommandBuffers[cb];
        if (cmdbuffer.iContainsUnsupportedCommands)
            {
            hasUnsupportedCommands = ETrue;
            break;
            }
        }
        
    THuiMemoryLevel memoryLevel;
    if ( iCanvasVisual ) // in constructor, iCanvasVisual == NULL
        {
        memoryLevel = iCanvasVisual->Env().MemoryLevel();
        }
    else
        {
        memoryLevel = CHuiStatic::Env().MemoryLevel();
        }

    CHuiCanvasWsGc* oldGc = iCanvasWsGc;

    if (memoryLevel <= EHuiMemoryLevelLowest)
        {
        if (!iCanvasWsGc || iCanvasWsGc != iCanvasWsBitGc)
            {
            // Fallback to the BIT GDI mode
            if (!iCanvasWsBitGc)
                {
                iCanvasWsBitGc = CHuiCanvasWsBitGc::NewL();
                }        
            iCanvasWsGc = iCanvasWsBitGc;
            // Must redraw all buffers to render buffer at next frame
            RenewAllBuffers();             
            }
        }
    else if (hasUnsupportedCommands && (!iCanvasWsGc || 
             iCanvasWsGc != iCanvasWsSwGc))
        {
        // Fallback to the SW mode
        if (!iCanvasWsSwGc)
            {
            iCanvasWsSwGc = CHuiCanvasWsSwGc::NewL();     
            }        
        iCanvasWsGc = iCanvasWsSwGc;
        // Must redraw all buffers to render buffer at next frame
        RenewAllBuffers();         
        }
    else if (!hasUnsupportedCommands && (!iCanvasWsGc || 
             iCanvasWsGc != iCanvasWsHwGc))
        {
        // Return to the HW accelerated mode
        if (!iCanvasWsHwGc)
            {
            iCanvasWsHwGc = CHuiCanvasWsHwGc::NewL();     
            }                
        iCanvasWsGc = iCanvasWsHwGc;
        // Must redraw all buffers to render buffer at next frame
        RenewAllBuffers();         
        }
    else
        {
        // We are good
        }        
        
    // Clear caches of non-used GCs
    if ( oldGc && oldGc != iCanvasWsGc )
        {
        oldGc->ClearCache();
        
        // delete SW rendering GC when not needed
        if ( oldGc == iCanvasWsBitGc ) 
            {
            delete iCanvasWsBitGc;
            iCanvasWsBitGc = NULL;
            }
        }

    if ( iCanvasWsGc )
        {
        // Forward 'enable render buffer' setting to new GC.
        iCanvasWsGc->EnableRenderbuffer( iEnableRenderBuffer );
        }

    #ifdef HUI_DEBUG_TRACK_DRAWING
    if (!iCanvasDebugWsGc)
        {
        iCanvasDebugWsGc = CHuiCanvasDebugWsGc::NewL( iCanvasWsGc, *TTlsData::CommandDebugger() );
        }
    else if(iCanvasWsGc!=iCanvasDebugWsGc) 
        {
        iCanvasDebugWsGc->SetInternalGc(iCanvasWsGc);
        }
    
    iCanvasWsGc = iCanvasDebugWsGc;
    #endif
    
    AMT_MAP_CANVAS_WS_PAINTER_SELECT_GC();
    }

void CHuiCanvasWsPainter::RenewAllBuffers()
    {
    ClearAllBufferStatusFlags(EHuiCanvasBufferStatusAll);
    SetAllBufferStatusFlags(EHuiCanvasBufferStatusNew);                
    
    if (iCanvasVisual)
        {
        iCanvasVisual->SetChanged();
        }    
    }
	
void CHuiCanvasWsPainter::UpdateBufferUpdateRegions(TPoint aPos)
	{
	// iUpdateRegion is in screen coordinates. If visual moves position, iUpdateRegion 
	// should be updated as well. Otherwise visual will encounter clipping.
    TBool updated = EFalse;
	
	for (TInt cb = 0; cb < iCommandBuffers.Count(); cb++)
        {
		if (iCommandBuffers[cb]->iPositionForUpdateRegion != aPos && !iCommandBuffers[cb]->iUpdateRegion.IsEmpty() )
			{
			updated = ETrue;
			
			TPoint deltaPos = aPos - iCommandBuffers[cb]->iPositionForUpdateRegion;
			iCommandBuffers[cb]->iUpdateRegion.Offset(deltaPos);
			iCommandBuffers[cb]->iPositionForUpdateRegion = aPos;
			}
		
		if (updated)
		    {
            // If one command buffer is drawn, then all following command
            // buffers must be redrawn as well.
            iCommandBuffers[cb]->ClearStatusFlags(EHuiCanvasBufferStatusAll);
            iCommandBuffers[cb]->SetStatusFlags(EHuiCanvasBufferStatusNew);			
            }
        }
    }

void CHuiCanvasWsPainter::SetMemoryLevel(THuiMemoryLevel /*aLevel*/)
    {
    TRAP_IGNORE(SelectGcL());
    }