/*
* Copyright (c) 2006-2008 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:   Implementation of CHuiDisplay, a drawing buffer into which a 
*                the toolkit contents (visuals) are drawn.
*
*/



#include "uiacceltk/HuiDisplay.h"  // Class definition
#include "uiacceltk/HuiStatic.h"
#include "HuiRenderPlugin.h"
#include "HuiRenderSurface.h"
#include "uiacceltk/HuiEnv.h"
#include "HuiRosterImpl.h"
#include "uiacceltk/HuiSkin.h"
#include "uiacceltk/HuiTransformation.h"
#include "uiacceltk/HuiUtil.h"
#include "uiacceltk/HuiTexture.h"
#include "uiacceltk/HuiProbe.h"
#include "uiacceltk/HuiS60Skin.h"
#include "uiacceltk/HuiGc.h"
#ifndef __SERIES60_30__ 
#include "HuiTargetBitmap.h"
#endif
#include "uiacceltk/HuiControlGroup.h"
#include "alf/alfconstants.h" 

#ifdef RD_ALF_IN_PLATFORM            
#include <displaylayoutmetrics.cdl.h>
#endif // RD_ALF_IN_PLATFORM            

#include <AknsRendererWrapper.h>
#include <AknsDrawUtils.h>

#include <coecntrl.h>
#include <uiacceltk/huidisplaybackgrounditem.h>
#include "huiskinbackroundlayout.h"
#include "HuiFxEngine.h"
#include "huiextension.h"

const TUid KHuiInternalFbsBitmapBufferGcUid = {0x2000e5a3}; 

//#define HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL


// *** Class CHuiFbsBitmapBufferGc

class CHuiFbsBitmapBufferGc: public CBase, public MHuiFbsBitmapBufferGc
    {
    public:
    	CHuiFbsBitmapBufferGc(CFbsBitmap* aBitmap) :iBitmap(aBitmap) {};
    
    private: // From MHuiFbsBitmapBufferGc
    	void ReleaseGc(); 
    	CFbsBitmap* Bitmap(); 

    private:
    	CFbsBitmap* iBitmap; // not owned  
    };


void CHuiFbsBitmapBufferGc::ReleaseGc()
	{
	// Line "delete(this)" should always be the last line in this method.
	// If you change this method behaviour make sure you know what caveats "delete(this)" has.
	delete(this); 
	}

CFbsBitmap* CHuiFbsBitmapBufferGc::Bitmap()
	{
	return iBitmap; 
	}

// *** Class CHuiDisplay

CHuiDisplay::CHuiDisplay(CHuiEnv& aEnv, RWindow* aNativeWindow, TInt aDisplayType, TUid aBackBufferUid )
          : iEnv(aEnv),
          iDisplayType(aDisplayType),
          iActive(ETrue),
          iBackgroundColor(KRgbBlack),
          iUpdateRenderState(ETrue),
          iUsageHint(EHuiDisplayUsageGeneric),
          iOnForeground(ETrue),
          iScreenBufferUid(aBackBufferUid),
          iUseTransformedDirtyRegions(EFalse),
          iDrawVisualOutline( EDrawVisualOutlineNone ),
          iNativeWindow(aNativeWindow)
    {
    }

CHuiDisplay::CHuiDisplay(CHuiEnv& aEnv, CCoeControl* aNativeControl, TInt aDisplayType, TUid aBackBufferUid )
        : iEnv(aEnv),
          iDisplayType(aDisplayType),
          iNativeControl(aNativeControl),
          iSize(0, 0),
          iActive(ETrue),
          iBackgroundColor(KRgbBlack),
          iUpdateRenderState(ETrue),
          iUsageHint(EHuiDisplayUsageGeneric),
          iOnForeground(ETrue),
          iScreenBufferUid(aBackBufferUid),
          iUseTransformedDirtyRegions(EFalse),
          iDrawDirtyRegions( EFalse ),
          iDrawVisualOutline( EDrawVisualOutlineNone )
    {
    }


void CHuiDisplay::ConstructL(const TRect& aRect, CHuiRoster* aSharedRoster)
    {
    HUI_DEBUG1(_L("CHuiDisplay::ConstructL - Free memory in beginning: %i"), HuiUtil::FreeMemory());
    
    // Register this display to receive foreground lost / gained events.
/*    CCoeEnv* coeEnv = CCoeEnv::Static();
    if(coeEnv && NativeWindow())
        {
        coeEnv->AddMessageMonitorObserverL(*this);
        NativeWindow()->EnableVisibilityChangeEvents();
        }
*/    

    iSize = aRect.Size();

    // Create a rendering surface.
    iRenderSurface = CHuiStatic::Renderer().CreateRenderSurfaceL(*this);
    
    iCurrentDirtyRegions = &iDirtyRegions;
    
    // Preserve previous dirty rect info only if the surface uses both dirty rects and double 
    // buffering
    TUint flags = MHuiRenderSurface::EFlagUseDirtyRects | MHuiRenderSurface::EFlagUseDoubleBuffering;
    TBool preservePreviousDirtyRectInfo = ((iRenderSurface->Flags() & flags) == flags);

    if (preservePreviousDirtyRectInfo)
   		{
    	iPreviousDirtyRegions = &iDirtyRegions2;
   		}
    		 
    // Create a control roster.
    if(aSharedRoster)
        {
        iRoster.Set(aSharedRoster, EHuiDoesNotHaveOwnership);
        }
    else
        {
        // Construct a private roster.
        CHuiRosterImpl* roster = new (ELeave) CHuiRosterImpl(this);
        iRoster.Set(roster, EHuiHasOwnership);
        }

    // Transformation for the entire display.
    iTransform = CHuiTransformation::NewL();
    // Window transformation for the entire display.
    iWindowTransform = CHuiTransformation::NewL();

	SetScreenBufferLock(EFalse);

    // Create a graphics context.
    iGc = CHuiStatic::Renderer().CreateGcL();

    HUI_DEBUG1(_L("CHuiDisplay::ConstructL - Free memory after GC created: %i"), HuiUtil::FreeMemory());

    SetVisibleArea(TRect(TPoint(0, 0), iSize));

    HUI_DEBUG1(_L("CHuiDisplay::ConstructL - Free memory after surface created: %i"), HuiUtil::FreeMemory());
    
    if ( !CHuiStatic::Renderer().Allows( EHuiRenderPluginAllowPBufferSurfaces ) )
    // There is no default render surface, so make this one current 
    // immediately to enable texture loading.
        {
        iRenderSurface->MakeCurrent();
        }
    
    // When dirty regions are transformed it is possible to avoid
    // full display refresh in many cases -> better performance.
    iGc->EnableTransformedClippingRects(iUseTransformedDirtyRegions);

    HUI_DEBUG1(_L("CHuiDisplay::ConstructL - Free memory when exiting ConstructL: %i"), HuiUtil::FreeMemory());
    }


EXPORT_C CHuiDisplay::~CHuiDisplay()
    {
    HUI_DEBUG1(_L("CHuiDisplay %x destructor"), this);

    // Unregister this display from foreground gained / lost events.
//    CCoeEnv* coeEnv = CCoeEnv::Static();
//    if(coeEnv && NativeWindow())
//        {
//        coeEnv->RemoveMessageMonitorObserver(*this);
//        }

    // Notify observers of deletion.
    
   	if(iScreenBufferObserver)
		{
		iScreenBufferObserver->HandleScreenBufferEvent(iScreenBufferUid, MHuiScreenBufferObserver::EDeleted);
		}
 
    for(TInt i = 0; i < iDeletionObservers.Count(); ++i)
        {
        iDeletionObservers[i].NotifyDisplayDeletion(*this);
        }
    iDeletionObservers.Reset();
    iRefreshObservers.Reset();
    iVisibleAreaObservers.Reset();
    iRosterObservers.Reset();

    iDirtyRegions.Close();
    iDirtyRegions2.Close();
    if ( iCurrentDirtyRegions )
        {
        iCurrentDirtyRegions->Close();
        }
    iCurrentDirtyRegions = NULL;
    
    if ( iPreviousDirtyRegions )
        {
        iPreviousDirtyRegions->Close();
        }
    iPreviousDirtyRegions = NULL;

    delete iRenderSurface;
    iRenderSurface = NULL;

    delete iGc;
    iGc = NULL;

    delete iTransform; 
    iTransform = NULL;

    delete iWindowTransform;
    iWindowTransform = NULL;
    
    iEnv.RemoveDisplay(*this);
    
    iNativeControl = NULL;
    
    iBackgroundItems.Close();
    
    delete iForegroundTexture;

    delete iForegroundBitmapGc;
    delete iForegroundBitmapDevice;
    iForegroundBitmap = NULL;
    }

TReal32 CHuiDisplay::UnitValue() const
    {
#ifdef RD_ALF_IN_PLATFORM            
    // this will be correct according to the currently loaded layout pack for the current display
    if (CCoeEnv::Static())
        {
        return Display_Layout_Metrics::UnitValue();
        }
    else
        {
        return 1.0f;
        }
#else // RD_ALF_IN_PLATFORM            
    // not supported
    return 1.0f;
#endif // RD_ALF_IN_PLATFORM            
    }

void CHuiDisplay::MonitorWsMessage(const TWsEvent& aEvent)
    {
	switch(aEvent.Type())
	    {
        case EEventWindowVisibilityChanged:
            {
            const TBool wasOnForeground = iOnForeground;
            
//            iOnForeground = !(aEvent.VisibilityChanged()->iFlags&TWsVisibilityChangedEvent::ENotVisible);
            
            if ( !wasOnForeground && iOnForeground )
                {
                // Becomes visible, force refresh. 
                // This is needed for example in case of resolution changes.
                SetDirty();
                }
            break;
            }
            
      	default:
        	break;              
	    }
    }


CHuiGc* CHuiDisplay::Gc()
    {
    ASSERT(iGc != NULL);
    
    return iGc;
    }
    
EXPORT_C CCoeControl* CHuiDisplay::NativeControl()
    {
    return iNativeControl;
    }


EXPORT_C RDrawableWindow* CHuiDisplay::NativeWindow()
    {
    if (iNativeWindow)
        {
        return iNativeWindow;
        }
                
    else if(iNativeControl)
        {
        return iNativeControl->DrawableWindow();
        }
        
    return 0;
    }


EXPORT_C CHuiEnv& CHuiDisplay::Env()
    {
    return iEnv;
    }


EXPORT_C MHuiRenderSurface& CHuiDisplay::RenderSurface() const
    {
    return *iRenderSurface;
    }


EXPORT_C CHuiRoster& CHuiDisplay::Roster()
    {
    return iRoster.Ref();
    }


EXPORT_C const CHuiRoster& CHuiDisplay::Roster() const
    {
    return iRoster.Ref();
    }


EXPORT_C void CHuiDisplay::Show(TBool aShow)
    {
    iRenderSurface->HandleVisibilityEvent(aShow);

    // Update projection and GC state on the next refresh.
    iUpdateRenderState = ETrue;
    }


CHuiRosterImpl& CHuiDisplay::RosterImpl() const
    {
    return STATIC_CAST(CHuiRosterImpl&, iRoster.NonConstRef());
    }


EXPORT_C void CHuiDisplay::SetSizeL(const TSize& aSize)
    {
    iSize = aSize;

    // Update projection and GC state on the next refresh.
    iUpdateRenderState = ETrue;

    if(iRenderSurface)
        {
        iRenderSurface->SetSizeL(iSize);
        }
    }


EXPORT_C TSize CHuiDisplay::Size() const
    {
    return iSize;
    }


EXPORT_C TRect CHuiDisplay::VisibleArea() const
    {
    return iGc->DisplayArea();
    }


EXPORT_C void CHuiDisplay::SetVisibleArea(const TRect& aArea)
    {
    if(iGc)
        {
        // If clipping has been defined for visible are, it is now invalid so disable.
        SetVisibleAreaClippingRect(TRect(0,0,0,0));
        
        iGc->SetDisplayArea(aArea);
        // Make sure everything gets redrawn.
        SetDirty();
        
  		// Can change the roster rect only if the roster is own
   		// \todo This should be prevented also for other shared roster types.
       	RosterImpl().SetRect(aArea);

        // Update projection and GC state on the next refresh.
        iUpdateRenderState = ETrue;

        // Inform observers.
        for(TInt i = 0; i < iVisibleAreaObservers.Count(); ++i)
            {
            iVisibleAreaObservers[i].NotifyDisplayVisibleAreaChanged(*this);
            }
        }
    }


EXPORT_C void CHuiDisplay::Activate(TBool aActivate)
    {
    iActive = aActivate;

    if(iActive)
        {
        // This is the display now using the roster. Only meaningful when the
        // roster is shared between many displays.
        RosterImpl().SetDisplay(this);
        }
    }


EXPORT_C TBool CHuiDisplay::Active() const
    {
    return iActive;
    }


EXPORT_C void CHuiDisplay::SetOrientation(CHuiGc::TOrientation aOrientation)
    {
    if (iGc->Orientation() == aOrientation)
        {
        return;
        }
    
    iGc->SetOrientation(aOrientation);

    // The effective visible area, as seen by the UI, changes.
    RosterImpl().SetRect(VisibleArea());
    for(TInt i = 0; i < iVisibleAreaObservers.Count(); ++i)
        {
        iVisibleAreaObservers[i].NotifyDisplayVisibleAreaChanged(*this);
        }

    SetDirty();

    // Update projection and GC state on the next refresh.
    iUpdateRenderState = ETrue;
    
    // Clear effect engine cache as it most likely now contains buffers which 
    // sizes are not very well reusable. It would be better to have "fifo" or
    // something in the cache implementation but until that just release everything here
    // when display layout changes.
    CHuiFxEngine* fxEngine = Env().EffectsEngine();  
    if (fxEngine)
        {
        fxEngine->ClearCache();
        }
    } 


EXPORT_C CHuiGc::TOrientation CHuiDisplay::Orientation() const
    {
    return iGc->Orientation();
    }


EXPORT_C void CHuiDisplay::SetDirty()
    {
    // Mark the entire display dirty.
    HUI_DEBUG(_L("CHuiDisplay::SetDirty() - called."));
   
    if ( iWholeDisplayAreaIsDirty )
        {
        return;
        }
   
    TRect displayArea = iGc->DisplayArea();
    AddDirtyRegion(displayArea, *iCurrentDirtyRegions);
    if (iPreviousDirtyRegions)
    	{
		AddDirtyRegion(displayArea, *iPreviousDirtyRegions);
    	}
    iEnv.ContinueRefresh();
    
    iWholeDisplayAreaIsDirty = ETrue;
    }


TBool CHuiDisplay::IsDirty() const
    {
    //iRoster->ScanDirty();
    //return iDirtyRegions.Count() > 0;

    /** @todo  Determine this better. There should be a way to quickly
               determine if the display needs to be updated; although
               a visual change scan is also a possiblity if it is done
               once per frame. */

    return iActive;
    }


void CHuiDisplay::AddDirtyRegion(const TRect& aDirtyRegion)
    {        
    // Whole screen has been set dirty, no need to add new areas.
    if (iWholeDisplayAreaIsDirty && iGotDirtyReports)
        {
        return;    
        }

    TRect clippedDirtyRect = aDirtyRegion;            
    
    if (UseTransformedDirtyRegions())
        {
        TransformDirtyRect(clippedDirtyRect);
        }
    
    ClipDirtyRect(clippedDirtyRect);
        
    // If whole screen is set dirty, update flag which can be used to avoid 
    // further unnecessary dirty area calculations
    if (iGc && (iGc->DisplayArea() ==  clippedDirtyRect))
        {
        iWholeDisplayAreaIsDirty = ETrue;    
        }        

    // At least one dirty region was reported.
    iGotDirtyReports = ETrue;

    AddDirtyRegion(clippedDirtyRect, *iCurrentDirtyRegions);
    }


void CHuiDisplay::CombineAndAddDirtyRegion(const TRect& aPrevDirtyRegion, TRect& aDirtyRegion)
    {   
    // aPrevDirtyRegion has already been transformed, but aDirtyRegion is not (yet)
    // transformed.

    TRect dirtyRect = aDirtyRegion;            
    
    if (!dirtyRect.IsEmpty() && UseTransformedDirtyRegions())
        {
        TransformDirtyRect(dirtyRect);
     	}

    TRect transformedNewDirtyRect = dirtyRect;            
              
    // If the whole display is not dirty, update current combined dirty region     
    if (!iWholeDisplayAreaIsDirty)
    	{
    	dirtyRect.BoundingRect(aPrevDirtyRegion);	
    
    	ClipDirtyRect(dirtyRect);
    	
     	if (iGc && (iGc->DisplayArea() ==  dirtyRect))
        	{
    		// If whole screen is set dirty, update flag which can be used to avoid 
    		// further unnecessary dirty area calculations
        	iWholeDisplayAreaIsDirty = ETrue;    
        	}        

    	// At least one dirty region was reported.
    	iGotDirtyReports = ETrue;         	
   		AddDirtyRegion(dirtyRect, *iCurrentDirtyRegions);
    	}
    // We must only transform the (new) dirtyregion, not combine or anything else here
    aDirtyRegion = transformedNewDirtyRect;
    }


void CHuiDisplay::AddDirtyRegion(const TRect& aDirtyRegion, RDirtyRegions& aRegions, TBool /*aGrow*/)
    {
    TBool combined = ETrue;
    TInt i = 0;
    TInt k = 0;

    aRegions.Append(aDirtyRegion);

    // Combine overlapping regions.
    while(combined && aRegions.Count() > 1)
        {
        combined = EFalse;

        // Check that none of the regions overlap each other.
        /** @todo Performance? */
        for(i = 0; i < aRegions.Count(); ++i)
            {
            TRect expanded = aRegions[i];
            expanded.Grow(20, 20); //(8, 8);

            for(k = i + 1; k < aRegions.Count(); ++k)
                {
                // E: comment out for lazy merging
                if(aRegions[k].Intersects(expanded))
                    {
                    // Remove the latter one.
                    aRegions[i].BoundingRect(aRegions[k]);
                    aRegions.Remove(k);
                    --k;
                    combined = ETrue;
                    }
                }
            }
        }
    }


TBool CHuiDisplay::Refresh()
    {
    HUI_DEBUGF(_L("CHuiDisplay::Refresh() - Entering."));
    HUI_PROBE_PROGRAMFLOW_ENTER(MHuiProbe::EProgramFlowPointRefresh)
    
#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
    RDebug::Print(_L("CHuiDisplay::Refresh: starting measuring."));
    TTime startTime;
    startTime.UniversalTime();
#endif
    
    
    // Prevent display refresh, if the display is on background.
    if(!iOnForeground || IsScreenBufferLocked())
        {
        return EFalse;
        }
    
    TBool useDirtyRects = (RenderSurface().Flags() & MHuiRenderSurface::EFlagUseDirtyRects) 
    					  == MHuiRenderSurface::EFlagUseDirtyRects;
 	
    iWholeDisplayAreaIsDirty = EFalse;    
    
    if(iUpdateRenderState)
        {
        // Set state when requested.
        iGc->InitState();
        iGc->SetProjection();

        iUpdateRenderState = EFalse;
        }

    // Let the skin know that we're now drawing in this context.
    iEnv.Skin().SetContext(*iGc);

    TRect displayArea = iGc->DisplayArea();

    // Notify observers of the display refresh.
    TInt i = 0;
    for(i = 0; i < iRefreshObservers.Count(); ++i)
        {
        iRefreshObservers[i].NotifyDisplayRefreshStarted(*this);
        }
#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
    TTime afterNotifiedTime;
    afterNotifiedTime.UniversalTime();
#endif


	if (IsDisplayTypeTvOut())
		{
		// Scale shared roster to Tv-out screen				
		TReal32 scaleFactorX = (TReal32)Size().iWidth / (TReal32)RosterImpl().Rect().Width();
		TReal32 scaleFactorY = (TReal32)Size().iHeight / (TReal32)RosterImpl().Rect().Height();					
		// Calculate window transformations		
    	iWindowTransform->LoadIdentity();
    	iWindowTransform->Scale(scaleFactorX, scaleFactorY, 1.f);
    	}

//	THuiRenderer renderer = iEnv.Renderer();
	TBool hasTransformations = iTransform->Count() != 0 || iWindowTransform->Count() != 0 || RosterImpl().HasTransformedControlGroups();
	TBool cantUseDirtyRectsInThisFrame = hasTransformations && !UseTransformedDirtyRegions();
	    
    // When refresh is forced, there is no need to scan dirty areas.
    if (iEnv.RefreshMode() != EHuiRefreshModeForced) 
        {
        // Flag that tells us if any dirty regions were reported for
        // this frame.
        iGotDirtyReports = (iCurrentDirtyRegions->Count() > 0);
        
        // Tell all visuals to post their dirty regions (for the current state).
        if (UseTransformedDirtyRegions())
            {
            RosterImpl().ScanTransformedDirty(*iGc, this);	         	        
            }
         else
            {
            RosterImpl().ScanDirty();	         	      
            }   

        if (!useDirtyRects || cantUseDirtyRectsInThisFrame || iEnv.EffectsEngine()->HasActiveEffects()) 
         	{         	
	        // Just redraw everything
	        iCurrentDirtyRegions->Reset();
	        AddDirtyRegion(displayArea, *iCurrentDirtyRegions, EFalse);
         	} 
        }
    else
        {
        iGotDirtyReports = ETrue;

        // Just redraw everything since determining dirty regions is
        // complicated with a transformed display.
        iCurrentDirtyRegions->Reset();
        AddDirtyRegion(displayArea);
        }

	// We can return now if there are no new or old dirty areas
	if (!iGotDirtyReports && (!iPreviousDirtyRegions || (iPreviousDirtyRegions->Count() == 0)))
		{
		iCurrentDirtyRegions->Reset();
		return EFalse;
		}

    // Form the real list of dirty regions by combining the dirty regions of
    // this frame and the previous frame (this is needed when buffer swapping
    // is used; with buffer copying a single list of dirty regions would
    // suffice).
    RDirtyRegions dirty;
    for(i = 0; i < iCurrentDirtyRegions->Count(); ++i)
        {
        dirty.Append((*iCurrentDirtyRegions)[i]);
        }
    if (iPreviousDirtyRegions)
    	{
    	for(i = 0; i < iPreviousDirtyRegions->Count(); ++i)
        	{
        	AddDirtyRegion((*iPreviousDirtyRegions)[i], dirty, EFalse);
        	}
    	}

	// Do initializations for new frame
	// initnewframe may clear the screen, and it may be that
	// the clipping rectangle is not set up correctly
	// atleast if the dirty area tracking is on..
	iGc->SetPenColor(iBackgroundColor);
	iGc->InitNewFrame();

    if ( iDrawDirtyRegions )
        {
        // Show dirty. 
        // This will draw the whole background with black.
        iGc->SetPenColor(KRgbBlack);
        iGc->Disable(CHuiGc::EFeatureClipping);
        iGc->Clear();
        }

		
    // Set up clipping.
    TInt markedClipStackCount = iGc->ClipStackCount();
    if(useDirtyRects)
    	{
	    iGc->Enable(CHuiGc::EFeatureClipping);
    	}

	// Assume that we succeed to clean the dirty regions
    TBool dirtyRegionsCleaned = ETrue;

	// Set dirty rect in render surface to minimize screen update
	// Only implemented for BitGdi renderer for now
    TRect mergedDirtyRect;
    if (dirty.Count() > 0)
    	{
    	mergedDirtyRect = dirty[0];
    	}
    	
	if (useDirtyRects)
	    {
		// When Bitgdi renderer used set dirty rect in render surface
		// to minimize screen update in CHuiBitgdiRenderSurface::SwapBuffers
	    if (dirty.Count() == 1)
		    {
            ClipDirtyRect(mergedDirtyRect, VisibleAreaClippingRect());
            iRenderSurface->SetDirtyRect(mergedDirtyRect);
		    }
		else if (dirty.Count() > 1) 
		    {
			for(i = 1; i < dirty.Count(); ++i)
				{
				TRect r(dirty[i]);
				// check top left corner to expand or not
				if (r.iTl.iX < mergedDirtyRect.iTl.iX)
				    {
				    mergedDirtyRect.iTl.iX = r.iTl.iX;
				    }
				if (r.iTl.iY < mergedDirtyRect.iTl.iY)
				    {
				    mergedDirtyRect.iTl.iY = r.iTl.iY;
				    }
				// check bottom right corner to expand or not
				if (mergedDirtyRect.iBr.iX < r.iBr.iX)
				    {
				    mergedDirtyRect.iBr.iX = r.iBr.iX;
				    }
				if (mergedDirtyRect.iBr.iY < r.iBr.iY)
				    {
				    mergedDirtyRect.iBr.iY = r.iBr.iY;
				    }
				}
				
            ClipDirtyRect(mergedDirtyRect, VisibleAreaClippingRect());
            iRenderSurface->SetDirtyRect(mergedDirtyRect);
		    }
        else
            {
            // for PC lint
            }
            
        if ( iDrawDirtyRegions )
	        {
            // This will disable the clipping of the frame buffer when 
            // blitting on the screen.
	        iRenderSurface->SetDirtyRect(displayArea);
            }
	    }	   

	// Merge into max one dirty area when HW accelrated drawing is used
	if (useDirtyRects && IsRendererHWAccelerated())
	    {
	    dirty.Reset();
	    dirty.Append(mergedDirtyRect);
	    }
	
#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
    RDebug::Print(_L("CHuiDisplay::Refresh: Merged dirty rect: %d %d %d %d"), 
            mergedDirtyRect.iTl.iX,  
            mergedDirtyRect.iTl.iY,  
            mergedDirtyRect.iBr.iX,  
            mergedDirtyRect.iBr.iY);  
#endif	
	
    // Usually there is only one dirty region (if any).
    for(i = 0; i < dirty.Count(); ++i)
        {
        // Set up the clipping rectangle.
        TRect dirtyRect = dirty[i];
        ClipDirtyRect(dirtyRect, VisibleAreaClippingRect());
        
        iGc->PushClip();
        iGc->Clip(dirtyRect);        
        
        if ( iForegroundBitmapGc && !RosterImpl().IsVisibleContentFrozen() )
            {
            // If we are in SW rendering mode, then SW bitmap may be blended.
            // However, it's possible that nothing is drawn below, so clear
            // background.
            const TRgb oldBgColor = iBackgroundColor;
            iBackgroundColor = KRgbBlack;
            iBackgroundColor.SetAlpha(0);
            ClearWithColor( dirtyRect );
            iBackgroundColor = oldBgColor;
            }
                
        // Clear background for the dirty area
        if (iBackgroundItems.Count() != 0)
            {
            ClearWithBackgroundItems(dirtyRect);    
            }
        else
            {
            switch (iClearBackground)
                {
                case EClearWithColor:
                    {
                    ClearWithColor(dirtyRect);                            
                    break;    
                    }
                case EClearWithSkinBackground:
                    {
                    ClearWithSkinBackground(dirtyRect);                                                    
                    break;    
                    }
                case EClearNone:
                default:
                    {
                    // Don't do anything
                    break;    
                    }                                                
                }                                    
            }                                        
        
        if ( iForegroundBitmapGc && iForegroundTextureTransparency )
            {
            // There is ALF content in the background, we have to
            // clear foreground bitmap.
            
            iForegroundBitmapGc->Reset();
            TRgb clearColor = KRgbBlack;
            clearColor.SetAlpha(0x00);
                    
	        iForegroundBitmapGc->SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
            iForegroundBitmapGc->SetPenColor(clearColor);
            iForegroundBitmapGc->SetBrushColor(clearColor);
            iForegroundBitmapGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
  	        iForegroundBitmapGc->Clear();
  	        iForegroundBitmapGc->Reset();
            }
        		
        for(TInt i = 0; i < iRosterObservers.Count(); i++)
            {
            iRosterObservers[i].NotifyRosterDrawStart(*this);
            }
        
		// Prepare dirty visuals for drawing
		// Draw only if the prepare was successful
		if (RosterImpl().PrepareDraw())
			{
	        // Draw all the dirty visuals (that are touching dirty regions).
	        iGc->Enable(CHuiGc::EFeatureBlending);
            RosterImpl().Draw(*iGc, this);                    
			}
		else 
			{
		    HUI_DEBUGF(_L("CHuiDisplay::Refresh() - Failed to prepare drawing!"));
	        dirtyRegionsCleaned = EFalse;			
			}

        for(TInt i = 0; i < iRosterObservers.Count(); i++)
            {
            iRosterObservers[i].NotifyRosterDrawEnd(*this);
            }
		
		if (iForegroundTexture)
		    {
		    UpdateForegroundTexture(dirtyRect);
		    DrawForegroundTexture();
		    }
		
        // Return to the clipping rectangle that was in use previously.
        iGc->PopClip();
        }

    dirty.Reset();

    // There must be no disparity in the number of pushed clipping rectangles.
    // (equivalent to __ASSERT_ALWAYS)
    if(iGc->ClipStackCount() > markedClipStackCount)
        {
        THuiPanic::Panic(THuiPanic::EDisplayClipStackUnpopped);
        }
    if(iGc->ClipStackCount() < markedClipStackCount)
        {
        THuiPanic::Panic(THuiPanic::EDisplayClipStackEarlyPop);
        }

    // Reset and flip if we managed to clean (draw) everything
	if (iPreviousDirtyRegions && dirtyRegionsCleaned && iCurrentDirtyRegions->Count() > 0) 
		{
    	RDirtyRegions* tmp = iPreviousDirtyRegions;
    	iPreviousDirtyRegions = iCurrentDirtyRegions;
    	iCurrentDirtyRegions = tmp;
		}
		
	// Clear current dirty regions	
	iCurrentDirtyRegions->Reset();
	
	// Trick to swap gles buffers if we are drawing idle screens before refresh loop is going to
	// sleep. 
	if(	IsRendererHWAccelerated() && !iGotDirtyReports && !iScreenBufferObserver) 
    		{
	    	//RenderSurface().SwapBuffers(); [ohi]
	    	}
	    	
	// Tell the screen buffer observer that the buffer is complete 
	if(iScreenBufferObserver)
		{
		SetScreenBufferLock(ETrue); // the observer should do unlock!
		
		TRect rect(VisibleArea()); // This is not the real display rect in ALF display case(!)
		TRect dirtyRect(mergedDirtyRect);
		
		// Update screen buffer GC bitmap
		if (DisplayType() != CHuiDisplay::EDisplayOffScreenBuffer)
			{
			TRAP_IGNORE(CHuiStatic::Renderer().UpdateOffScreenBitmapL(*this));			
			}
						
		if (iScreenBufferObserver->ScreenBufferComplete(iScreenBufferUid, rect, dirtyRect))
			{
			SetScreenBufferLock(EFalse);
			}
		}

    iWholeDisplayAreaIsDirty = EFalse;    
	
    HUI_PROBE_PROGRAMFLOW_EXIT(MHuiProbe::EProgramFlowPointRefresh)
    HUI_DEBUGF(_L("CHuiDisplay::Refresh() - Exiting."));

#ifdef HUI_DEBUG_PRINT_PERFORMANCE_INTERVAL
    TTime endTime;
    endTime.UniversalTime();
    TInt timeInMs =  endTime.MicroSecondsFrom( startTime ).Int64()/1000;           
    TInt notifyTimeInMs =  afterNotifiedTime.MicroSecondsFrom( startTime ).Int64()/1000;           
    TInt restTimeInMs =  endTime.MicroSecondsFrom( afterNotifiedTime ).Int64()/1000;           

    RDebug::Print(_L("CHuiDisplay::Refresh: took %i ms"), timeInMs);
    RDebug::Print(_L("CHuiDisplay::Refresh: notify refresh observers took %i ms"), notifyTimeInMs);
    RDebug::Print(_L("CHuiDisplay::Refresh: rest took %i ms"), restTimeInMs);

#endif


    // If something was reported (even if eventually clipped), we'll say that
    // there was some activity. If it was clipped and did not show up on the
    // display, it may soon (re)appear, so let's be cautious.
    return iGotDirtyReports;
    }


EXPORT_C CHuiTransformation& CHuiDisplay::Transformation() const
    {
    return *iTransform;
    }


EXPORT_C void CHuiDisplay::SetClearBackgroundL(TClearMode aClearBackground)
    {
    // Make sure that background resource allocation is succeeded.
    if(aClearBackground == EClearWithSkinBackground)
        {
        iEnv.Skin().TextureL(EHuiSkinBackgroundTexture);
        }

    iClearBackground = aClearBackground;
    iBackgroundItems.Reset();
    }


EXPORT_C void CHuiDisplay::SetBackgroundColor(const TRgb& aBackgroundColor)
    {
    iBackgroundColor = aBackgroundColor;
    }


EXPORT_C void CHuiDisplay::SetUseDepth(TBool aUseDepth)
    {
    iUseDepth = aUseDepth;
    }


EXPORT_C TUint8* CHuiDisplay::CaptureLC(TSize& aSize) const
    {
    return iGc->CaptureLC(aSize);
    }


EXPORT_C void CHuiDisplay::SetQuality(THuiQuality aRenderingQuality)
    {
    if(iGc)
        {
        iGc->SetQuality(aRenderingQuality);
        SetDirty();
        }
    }


EXPORT_C THuiQuality CHuiDisplay::Quality() const
    {
    if(iGc)
        {
        return iGc->Quality();
        }
    return EHuiQualityAccurate;
    }


EXPORT_C void CHuiDisplay::Release()
    {      
    // Free the render surface.
    ASSERT(iRenderSurface != NULL);
    HUI_DEBUG(_L("CHuiDisplay::Release() - Releasing render surface."));    
    iRenderSurface->Release();
        
    HUI_DEBUG(_L("CHuiDisplay::Release() - Display released."));            
    }


EXPORT_C void CHuiDisplay::RestoreL()
    {
    HUI_DEBUG(_L("CHuiDisplay::RestoreL() - Restoring display resources."));    
    
    // Reconfigure graphics context when display is refreshed.
    iUpdateRenderState = ETrue;
    
    // Create a rendering surface.
    iRenderSurface->RestoreL();
    }


EXPORT_C TInt CHuiDisplay::DisplayType()
	{
	return iDisplayType;
	}
	
EXPORT_C TUid CHuiDisplay::ScreenBufferUid()
	{
	return iScreenBufferUid;
	}
	

EXPORT_C TBool CHuiDisplay::IsScreenBufferLocked() const
	{
	return iIsScreenBufferLocked;
	}
    
    
EXPORT_C void CHuiDisplay::SetScreenBufferLock(TBool aLock)
	{
	iIsScreenBufferLocked = aLock;
	}


EXPORT_C MHuiBufferDrawer* CHuiDisplay::GetDrawingInterface(const TUid& /*aInterfaceUid*/)
	{
	return (MHuiBufferDrawer*)NULL;
	}
	
	
EXPORT_C MHuiGc* CHuiDisplay::GetGraphicsContext(const TUid& aInterfaceUid)
	{
	MHuiGc* gc = NULL;
	if (aInterfaceUid == KHuiInternalFbsBitmapBufferGcUid)
		{
    	if (iEnv.Renderer() == EHuiRendererBitgdi) 
			{
			CFbsBitmap* backBuffer = iRenderSurface->BackBuffer()->FbsBitmap();
			CHuiFbsBitmapBufferGc* bitmapGc = new CHuiFbsBitmapBufferGc(backBuffer);
			gc =  (MHuiFbsBitmapBufferGc*) bitmapGc;
			}
        else
            {
            if ( DisplayType() != CHuiDisplay::EDisplayOffScreenBuffer )
			    {
			    gc =(MHuiFbsBitmapBufferGc*) new CHuiFbsBitmapBufferGc(
			        CHuiStatic::Renderer().OffScreenBitmap());
			    }
            }
		}
	return gc;     	
	}	
	
EXPORT_C void CHuiDisplay::AddScreenBufferObserverL(MHuiScreenBufferObserver* aObserver)
	{
	if (DisplayType() != CHuiDisplay::EDisplayOffScreenBuffer)
		{
		CHuiStatic::Renderer().EnableOffScreenBitmapL(0);
		}
								
	iScreenBufferObserver = aObserver;
	SetScreenBufferLock(EFalse); 
	}
	
	
EXPORT_C void CHuiDisplay::RemoveScreenBufferObserver()
	{
	iScreenBufferObserver = NULL;	
	
	if (DisplayType() != CHuiDisplay::EDisplayOffScreenBuffer)
		{
		CHuiStatic::Renderer().DisableOffScreenBitmap();
		}
	
	SetScreenBufferLock(EFalse); 
	}
     
     
EXPORT_C MHuiScreenBufferObserver*  CHuiDisplay::ScreenBufferObserver()
	{
	return iScreenBufferObserver;
	}
	

EXPORT_C void CHuiDisplay::DrawScreenBuffer() 
	{
	if (DisplayType() != CHuiDisplay::EDisplayOffScreenBuffer)
		{
		TRAP_IGNORE(CHuiStatic::Renderer().DrawOffScreenBitmapToWindowL(*this));			
		}					
	}


void CHuiDisplay::ClearChanged()
    {
    RosterImpl().ClearChanged();
    }
        
EXPORT_C void CHuiDisplay::SetUsageL(TUint aUsageHint)
    {
    iUsageHint = aUsageHint;    
    if (iRenderSurface)
        {
        iRenderSurface->HandleDisplayUsageChangeL();    
        }
    }

EXPORT_C TUint CHuiDisplay::Usage() const
    {
    return iUsageHint;     
    }
  
    
EXPORT_C TInt CHuiDisplay::GetPreferredTextureFormats(RPointerArray<CHuiDisplay::CTextureBitmapFormat>& aTextureFormats)
	{
    // Note: It would be better if preferred display mode was asked from the renderer itself
	TInt err = KErrNone;
	CHuiDisplay::CTextureBitmapFormat* format = NULL;
    if (!IsRendererHWAccelerated())
        {
        format = new CHuiDisplay::CTextureBitmapFormat(EColor64K, EGray256);
        if (format != NULL)
        	{
        	err = aTextureFormats.Append(format);
        	}
        }
    else
        {
        format = new CHuiDisplay::CTextureBitmapFormat(EColor16MA, ENone);
        if (format != NULL)
        	{
        	err = aTextureFormats.Append(format);
        	if (!err)
        		{
        		format = new CHuiDisplay::CTextureBitmapFormat(EColor64K, EGray256);
        		if (format != NULL)
        			{
        			err = aTextureFormats.Append(format);
        			}
        		}
        	}
        }
        			
	if (err)
    	{
        delete(format);
        }
        
    return (format == NULL) ? KErrNoMemory : err;	   
	}
  
    
CHuiTransformation& CHuiDisplay::WindowTransformation() const
    {
    return *iWindowTransform;        
    }

EXPORT_C TBool CHuiDisplay::IsDisplayTypeTvOut() const
   	{
   	return((iDisplayType == CHuiDisplay::EDisplayTvOut) || 
   	       (iDisplayType == CHuiDisplay::EDisplayTvOutWide) ||
   	       ((iDisplayType == CHuiDisplay::EDisplayNormal) && 
   	       ((iScreenBufferUid == KHuiUidBackBufferTvOutNormal) ||
   	        (iScreenBufferUid == KHuiUidBackBufferTvOutWide))));
   	}

TBool CHuiDisplay::IsRendererBitgdi() const
    {
    return (iEnv.Renderer() == EHuiRendererBitgdi);        
    }

TBool CHuiDisplay::IsRendererHWAccelerated() const
    {
    return (iEnv.Renderer() != EHuiRendererBitgdi);
    }

void CHuiDisplay::ClipDirtyRect(TRect& aRect)
    {
    // Check if dirty regions partially outside display are reported, limit
    // inside display area. 
    if(iGc)
        {            
        TRect displayRect = iGc->DisplayArea();        
        // If partially outside display area, we use intersection instead.
        if (aRect.Intersects(displayRect))
            {
            aRect.Intersection(displayRect);  
            }        
        }        
    }

void CHuiDisplay::TransformDirtyRect(TRect& aRect)
    {
    if ( iGc )
        {
        THuiRealRect realDirtyRect(aRect);
        iGc->TransformDirtyRect(realDirtyRect);
        aRect = TRect(HUI_ROUND_FLOAT_TO_INT(realDirtyRect.iTl.iX), HUI_ROUND_FLOAT_TO_INT(realDirtyRect.iTl.iY),
                      HUI_ROUND_FLOAT_TO_INT(realDirtyRect.iBr.iX), HUI_ROUND_FLOAT_TO_INT(realDirtyRect.iBr.iY));
        }
    }
    
TBool CHuiDisplay::UseTransformedDirtyRegions() const
    {
    return iUseTransformedDirtyRegions;    
    }
    
EXPORT_C void CHuiDisplay::ShowDirtyRegions( TBool aShow )
    {
    iDrawDirtyRegions = aShow;
    }

EXPORT_C void CHuiDisplay::SetDrawVisualOutline( TUint aDrawVisualOutline )
	{
	iDrawVisualOutline = aDrawVisualOutline;
	}
	 
TUint CHuiDisplay::DrawVisualOutline() const
	{
	return iDrawVisualOutline;
	}

TBool CHuiDisplay::IsDirtyScanNeeded() const
    {
    TUint flag = MHuiRenderSurface::EFlagUseDirtyRects;
	TBool useDirtyRects = (RenderSurface().Flags() & flag) == flag;
	return (useDirtyRects || !iGotDirtyReports);
    }
    
EXPORT_C void CHuiDisplay::SetBackgroundItemsL(const RArray<THuiDisplayBackgroundItem>& aItems)
    {
    iClearBackground = EClearNone;
    iBackgroundItems.Reset();
    for(TInt i = 0; i < aItems.Count(); ++i)
        {
        iBackgroundItems.AppendL(aItems[i]);
        }
    if (IsRendererHWAccelerated())
        {
        CHuiS60Skin* s60skin = static_cast<CHuiS60Skin*>(&iEnv.Skin());
        s60skin->UpdateBackgroundsL(iBackgroundItems);
        }
    SetDirty();    
    }

void CHuiDisplay::ClearWithColor(TRect aRect)
    {
    if (!IsRendererHWAccelerated())
        {
        BitgdiClearWithColor(aRect);    
        }
    else
        {
        HWAcceleratedClearWithColor(aRect);    
        }
    }

void CHuiDisplay::ClearWithSkinBackground(TRect aRect)
    {    
    if (!IsRendererHWAccelerated())
        {
        BitgdiClearWithSkinBackground(aRect);    
        }
    else
        {
        HWAcceleratedClearWithSkinBackground(aRect);    
        }
    }

void CHuiDisplay::ClearWithBackgroundItems(TRect aRect)
    {
    if (!IsRendererHWAccelerated())
        {
        BitgdiClearWithBackgroundItems(aRect);    
        }
    else
        {
        HWAcceleratedClearWithBackgroundItems(aRect);    
        }
    }

    
void CHuiDisplay::BitgdiClearWithColor(TRect /*aRect*/) 
    {
    iGc->Enable(CHuiGc::EFeatureClipping);
    iGc->Clear();        
    }
     
void CHuiDisplay::BitgdiClearWithSkinBackground(TRect aRect) 
    {
	CCoeControl* nativeControl = NativeControl();
   	CHuiS60Skin* s60skin = static_cast<CHuiS60Skin*>(&iEnv.Skin());
    CAknsBasicBackgroundControlContext* bgcontext = (CAknsBasicBackgroundControlContext*)s60skin->SkinControlContext();

    CFbsBitGc* bitGc = iRenderSurface->BackBuffer()->Gc();
	if (nativeControl)
		{
		bgcontext->SetRect(TRect(TPoint(0, -nativeControl->Position().iY), HuiUtil::ScreenSize()));
		}
	else
		{
		bgcontext->SetRect(TRect(TPoint(0, 0), HuiUtil::ScreenSize()));
		}

    // Draw the background onto the framebuffer
	MAknsSkinInstance* skin = CHuiStatic::SkinInstance();
	TPoint tl = aRect.iTl;
	TRect rect = aRect;
    bgcontext->SetBitmap(KAknsIIDQsnBgScreen);       

    AknsDrawUtils::DrawBackground(skin, bgcontext, NULL, 
    								*bitGc, tl, rect, 
                                  	KAknsDrawParamDefault);
    }

void CHuiDisplay::BitgdiClearWithBackgroundItems(TRect aRect)
    {
   	CHuiS60Skin* s60skin = static_cast<CHuiS60Skin*>(&iEnv.Skin());
    CAknsBasicBackgroundControlContext* bgcontext = (CAknsBasicBackgroundControlContext*)s60skin->SkinControlContext();

    CFbsBitGc* bitGc = iRenderSurface->BackBuffer()->Gc();
    THuiDisplayBackgroundItem item;    
    MAknsSkinInstance* skin = CHuiStatic::SkinInstance();

    for (TInt index = 0; index < iBackgroundItems.Count(); index++)
        {
        TRect clearRect = aRect;
        TRect skinRect = TRect(0,0,0,0);
        TRect dummy = TRect(0,0,0,0);

        item = iBackgroundItems[index];
        switch (item.ClearMode())
            {
            case EClearWithSkinBackground:
                if (skin)
                    {
                    GetRectForItem(item.SkinBackground(), dummy, skinRect);
                    bgcontext->SetRect(skinRect);
                    bgcontext->SetBitmap(item.SkinBackground());       
                    skinRect.Intersection(aRect);
                    skinRect.Intersection(item.Rect());
  		            AknsDrawUtils::DrawBackground(skin, bgcontext, NULL, 
							*bitGc, skinRect.iTl, skinRect, 
                          	KAknsDrawParamDefault);
                    break;
                    } // else fall through
            case EClearWithColor:
                clearRect.Intersection(item.Rect());
                if (!clearRect.IsEmpty())
                    {
                    bitGc->SetBrushColor(item.Color());
                    bitGc->Clear(clearRect);                                    
                    }
                break;
            case EClearNone:
            default: 
                // do nothing...
                break;
            }
        }
        
    }
    
void CHuiDisplay::HWAcceleratedClearWithColor(TRect /*aRect*/)
    {
    iGc->SetPenColor(iBackgroundColor);
    iGc->SetPenAlpha(iBackgroundColor.Alpha());
    iGc->Disable(CHuiGc::EFeatureBlending);
    iGc->Enable(CHuiGc::EFeatureClipping);
    iGc->Clear();
    }

void CHuiDisplay::HWAcceleratedClearWithSkinBackground(TRect /*aRect*/)
    {
    // Acquire background texture
    const CHuiTexture* backgroundTexture = NULL;
    TInt err = iEnv.Skin().GetTexture(EHuiSkinBackgroundTexture, backgroundTexture);
    if( err )
        {
        return;
        }

    // Apply background texture
    THuiImage background(*backgroundTexture);

    TPoint screenOrigin(0, 0);
    iRenderSurface->GetScreenOrigin(screenOrigin);
    // The origin is used to offset the background in the display's
    // rendering surface, so that the background's origin is in the
    // top left screen corner.
    screenOrigin.iX = -screenOrigin.iX;
    screenOrigin.iY = -screenOrigin.iY;

    iGc->SetPenColor(KRgbWhite);
    iGc->SetPenAlpha(255);
    iGc->SetAlign(EHuiAlignHLeft, EHuiAlignVTop);            
    iGc->Disable(CHuiGc::EFeatureBlending);
    iGc->Enable(CHuiGc::EFeatureClipping);            
    iGc->DrawImage(background, screenOrigin, background.Texture().Size());        
    }

void CHuiDisplay::HWAcceleratedClearWithBackgroundItems(TRect aRect)
    {
    THuiDisplayBackgroundItem item;
	CHuiS60Skin* s60skin = static_cast<CHuiS60Skin*>(&iEnv.Skin());
    CHuiTexture* backgroundTexture = NULL;
    for (TInt index = 0; index < iBackgroundItems.Count(); index++)
        {
        item = iBackgroundItems[index];
        switch (item.ClearMode())
            {
            case EClearNone:
                // do nothing...
                break;
            case EClearWithColor:
                // do not draw anything if background item rect does not intersect with dirty/ current clip rect
                if( item.Rect().Intersects(aRect)) 
                    {
                    iGc->SetPenColor(item.Color());
                    iGc->SetPenAlpha(255);
                    iGc->SetAlign(EHuiAlignHLeft, EHuiAlignVTop);            
                    iGc->Disable(CHuiGc::EFeatureBlending);
                    iGc->Enable(CHuiGc::EFeatureClipping);            
                    iGc->PushClip();
                    TRect temp = item.Rect();
                    temp.Intersection(aRect);
                    iGc->Clip(temp);
                    iGc->Clear();
                    iGc->PopClip();
                    }
                break;
            case EClearWithSkinBackground:
                 backgroundTexture = s60skin->BackgroundTexture(item.SkinBackground());
                 if (backgroundTexture)
                    {
                    TRect skinRect = s60skin->SkinRect(item.SkinBackground());
                    THuiImage background(*backgroundTexture);

                    TPoint screenOrigin(0, 0);
                    iRenderSurface->GetScreenOrigin(screenOrigin);
                    screenOrigin.iX = -screenOrigin.iX;
                    screenOrigin.iY = -screenOrigin.iY;
                    screenOrigin+=skinRect.iTl;
                    
                    // do not draw anything if background item rects does not intersect with dirty/ current clip rect
                    skinRect.Intersection(item.Rect());
                    if( skinRect.Intersects(aRect) )
                        {
                        iGc->SetPenColor(KRgbWhite);
                        iGc->SetPenAlpha(255);
                        iGc->SetAlign(EHuiAlignHLeft, EHuiAlignVTop);            
                        iGc->Disable(CHuiGc::EFeatureBlending);
                        iGc->Enable(CHuiGc::EFeatureClipping);            
                        iGc->PushClip();
                        skinRect.Intersection(aRect);
                        iGc->Clip(skinRect);
                        iGc->DrawImage(background, screenOrigin, background.Texture().Size());                     
                        iGc->PopClip();
                        }
                    }
                 break;                                                    
             }
        }             
    }
    
EXPORT_C void CHuiDisplay::SetVisibleAreaClippingRect(const TRect& 
        #ifndef SYMBIAN_BUILD_GCE  
        aVisibleAreaClippingRect 
        #endif  
        )
    {
// Visible area clipping is disabled in NGA    
#ifndef SYMBIAN_BUILD_GCE    
    iVisibleAreaClippingRect = aVisibleAreaClippingRect;   
#endif
    } 
    
TRect CHuiDisplay::VisibleAreaClippingRect() const
    {
// Visible area clipping is disabled in NGA    
#ifndef SYMBIAN_BUILD_GCE    
    if (IsVisibleAreaClippingEnabled())
        {
        return iVisibleAreaClippingRect;             
        }
    else
        { 
        return VisibleArea();             
        }        
#else
    return VisibleArea();                 
#endif    
    }
    
TBool CHuiDisplay::IsVisibleAreaClippingEnabled() const
    {
// Visible area clipping is disabled in NGA    
#ifndef SYMBIAN_BUILD_GCE    
    return iVisibleAreaClippingRect != TRect(0,0,0,0);            
#else
    return EFalse;
#endif
    }

void CHuiDisplay::ClipDirtyRect(TRect& aRect, TRect aClippingRect)
    {
    if (aRect.Intersects(aClippingRect))
        {
        aRect.Intersection(aClippingRect);  
        }                
    }
    
EXPORT_C void CHuiDisplay::SetForegroundTexture(CHuiTexture* aTexture)
    {
    if (iForegroundTexture != aTexture)
        {
        delete iForegroundTexture;
        iForegroundTexture = aTexture;
        SetDirty();
        }
    }

EXPORT_C CHuiTexture* CHuiDisplay::ForegroundTexture() const
    {
    return iForegroundTexture;
    }

EXPORT_C void CHuiDisplay::SetForegroundTextureOptions(TBool aTransparency)
    {
    iForegroundTextureTransparency = aTransparency;
    }

void CHuiDisplay::UpdateForegroundTexture(const TRect& aRect)
    {
    if (iForegroundTexture && iForegroundBitmap && !aRect.IsEmpty())
        {
        TRAP_IGNORE(DoUpdateForegroundTextureL(aRect));
        }
    }

void CHuiDisplay::DoUpdateForegroundTextureL(const TRect& aRect)
    {
    // First try to upload with faster mechanism
    THuiTexturePartialBitmapUploadParams params;
    params.iErrorCode = KErrNotSupported;
    params.iRect = aRect;
    params.iBitmap = iForegroundBitmap;
    TAny* ptr = &params;
    
    MHuiTexture* texture = iForegroundTexture;
    texture->TextureExtension(KHuiTexturePartialBitmapUploadUid, &ptr);
    if ( params.iErrorCode != KErrNone )
        {    
        iForegroundTexture->UploadL(*iForegroundBitmap, NULL);
        }
    }

void CHuiDisplay::DrawForegroundTexture()
    {
    if (iForegroundTexture && !RosterImpl().IsVisibleContentFrozen() )
        {
        THuiQuality originalQuality = iGc->Quality();
        if ( originalQuality != EHuiQualityFast )
            {
            // Enforce fast quality to be used - we want one to one mapping
            // & no antialiasing.
            iGc->SetQuality( EHuiQualityFast );
            }            
    
        // The following is similar to HWAcceleratedClearWithSkinBackground,
        // except blending is enabled.
        
        TPoint screenOrigin(0, 0);
        iRenderSurface->GetScreenOrigin(screenOrigin);
        screenOrigin.iX = -screenOrigin.iX;
        screenOrigin.iY = -screenOrigin.iY;

        THuiImage image = THuiImage(*iForegroundTexture);
        iGc->SetPenColor(KRgbWhite);
        iGc->SetPenAlpha(255);
        iGc->SetAlign(EHuiAlignHLeft, EHuiAlignVTop);            
        
        if ( iForegroundTextureTransparency )
            {
            iGc->Enable(CHuiGc::EFeatureBlending);
            }
        else
            {
            iGc->Disable(CHuiGc::EFeatureBlending);
            }
               
        iGc->Enable(CHuiGc::EFeatureClipping);            
        iGc->DrawImage(image, screenOrigin, image.Texture().Size());        

        if ( originalQuality != EHuiQualityFast )
            {
            // Restore original quality.
            iGc->SetQuality( originalQuality );
            }        
        }
    }
    
EXPORT_C void CHuiDisplay::SetForegroundBitmapL(CFbsBitmap* aBitmap)
    {
    // Note this method may be called with same bitmap, e.g.
    // when emulator display orientation is changed. Then we recreate
    // device & context in order to avoid panics.
    
    if ( !aBitmap )
        {
        delete iForegroundBitmapGc;
        iForegroundBitmapGc = NULL;
        delete iForegroundBitmapDevice;
        iForegroundBitmapDevice = NULL;
        iForegroundBitmap = NULL;
        }
    else
        {
        CFbsBitmapDevice* device = CFbsBitmapDevice::NewL( aBitmap );
        CleanupStack::PushL( device );
        
        CFbsBitGc* gc = NULL;
        User::LeaveIfError( device->CreateContext( gc ) );
        User::LeaveIfNull( gc );
        
        CleanupStack::Pop( device );
        
        iForegroundBitmap = aBitmap;
        delete iForegroundBitmapDevice;
        iForegroundBitmapDevice = device;
        delete iForegroundBitmapGc;
        iForegroundBitmapGc = gc;
        }
    }
    
EXPORT_C CFbsBitmap* CHuiDisplay::ForegroundBitmap() const
    {
    return iForegroundBitmap;
    }

EXPORT_C void CHuiDisplay::CopyScreenToBitmapL(CFbsBitmap* aBitmap)
    {
    MHuiRenderSurface* oldSurface = CHuiStatic::CurrentRenderSurface();
    RenderSurface().MakeCurrent();
    
    TInt err = iGc->CopyScreenToBitmap( aBitmap );
        
    if (oldSurface && oldSurface != &RenderSurface())
        {
        oldSurface->MakeCurrent();
        }
        
    User::LeaveIfError( err );
    }
