/*
* 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:   Implements CHuiVg10Gc, an OpenVG 1.0 version of the HUITK
*                graphics context.
*
*/



#include "HuiVg10Gc.h"  // Class definition
#include "HuiVg10RenderPlugin.h"
#include "HuiVg10Texture.h"
#include "HuiVg10RenderSurface.h"
#include "uiacceltk/HuiSegmentedTexture.h"
#include "uiacceltk/HuiFont.h"
#include "uiacceltk/HuiImage.h"
#include "uiacceltk/HuiTextMesh.h"
#include "uiacceltk/HuiCurvePath.h"
#include "uiacceltk/HuiTransformation.h"
#include "uiacceltk/HuiUtil.h"
#include "uiacceltk/HuiPanic.h"
#include "uiacceltk/huifixmath.h"
#include "HuiRenderSurface.h"

#include "huiextension.h"

#include <e32math.h>
#include <VG/vgu.h>
#ifdef __NVG
#pragma message( "NVG Defined!" )
    #include <nvg.h>
    #include <AknIconHeader.h>
    #include <AknIconUtils.h>
    #include "NVGIcon.h"
#endif

const TInt KHuiMaxVgScissorRects = 32;

/** Only render colorful rectangles instead of real graphics 
 *  content. Useful for debugging broken OpenVG drivers.
 */
//#define RENDER_DEBUG_RECTANGLES

CHuiVg10Gc* CHuiVg10Gc::NewL()
    {
    CHuiVg10Gc* self = CHuiVg10Gc::NewLC();
    CleanupStack::Pop(self);
    return self;
    }


CHuiVg10Gc* CHuiVg10Gc::NewLC()
    {
    CHuiVg10Gc* self = new (ELeave) CHuiVg10Gc();
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }


CHuiVg10Gc::CHuiVg10Gc()
        : CHuiGc()
    {
    }


void CHuiVg10Gc::ConstructL()
    {
    // iMatrix stack must be allocated here because InitState() is not allowed to leave
    
    iMatrixStack = CHuiMatrixStack::NewL();
#ifdef __NVG
    CHuiVg10RenderPlugin& renderer = (CHuiVg10RenderPlugin&) CHuiStatic::Renderer();
    iNvgEngine = &renderer.NvgEngine();
#endif    
    }


CHuiVg10Gc::~CHuiVg10Gc()
    {
#ifdef __NVG
    // Don't delete the iNvgEngine, it's owned by the plugin!
    iNvgEngine = NULL;
#endif    
    delete iMatrixStack;
    
    vgDestroyPath(iPath);
    vgDestroyPath(iImagePath);
    vgDestroyPath(iRectPath);
    vgDestroyPath(iRoundRectPath);
    vgDestroyPath(iLinePath);
    vgDestroyPath(iBorderPath);
    vgDestroyPath(iArcPath);
    vgDestroyPaint(iPaint);
    vgDestroyPaint(iGradientPaint);
    vgDestroyPath(iEllipsePath);
    }
    

void CHuiVg10Gc::Push(THuiGcMatrix aMatrix)
    {
    if (aMatrix == EHuiGcMatrixModel)
        {
        // Replicate the current OpenVG matrix to the matrix stack
        UpdateClientMatrix();
        iMatrixStack->Push();
        
        // Save the matrix flags
        iMatrixFlagsStack.Append(iMatrixFlags);
        }
    }


void CHuiVg10Gc::Pop(THuiGcMatrix aMatrix)
    {
    if (aMatrix == EHuiGcMatrixModel)
        {
        // Replicate the current matrix to OpenVG
        iMatrixStack->Pop();
        CHuiMatrixStack::TMatrix& matrix = iMatrixStack->Current();
        vgLoadMatrix((VGfloat*)matrix.iMatrix);
        
        // Restore the matrix flags
        iMatrixFlags = iMatrixFlagsStack[iMatrixFlagsStack.Count() - 1];
        iMatrixFlagsStack.Remove(iMatrixFlagsStack.Count() - 1);
        HUI_VG_INVARIANT();
        }
    }


void CHuiVg10Gc::LoadIdentity(THuiGcMatrix aMatrix)
    {
    if (aMatrix == EHuiGcMatrixModel)
        {
        vgLoadIdentity();
        
        TRect displayArea = DisplayArea();            
        TInt h = displayArea.Height();
        TInt w = displayArea.Width();

        // DisplayArea is rotated if orientation is rotated, so we must "counter rotate"
        // to avoid rotating too much.
        if(Orientation() == EOrientationCCW90 || Orientation() == EOrientationCW90)
            {
            TInt tmp = w;
            w = h;
            h = tmp;
            }
        
        // Flip the Y axis to match Hitchcock's coordinate system
        vgTranslate(0, h); 
        vgScale(1.0f, -1.0f);
        
        if(Orientation() == EOrientationCCW90)
            {
            // Rotate around origo and move back to displayarea
            vgRotate(90);
            vgTranslate(0, -w);
            }
        else if(Orientation() == EOrientationCW90)
            {            
            // Rotate around origo and move back to displayarea
            vgRotate(-90);
            vgTranslate(-h, 0);
            }
        else if (Orientation() == EOrientation180)
            {
            // Rotate around origo and move back to displayarea
            vgRotate(-180);
            vgTranslate(-w, -h);            
            }                   
        else
            {
            // Nothing to do ?
            }
        
        // Reset the flags for this matrix
        iMatrixFlags = 0;
        
        HUI_VG_INVARIANT();
        }
    }


void CHuiVg10Gc::Multiply(THuiGcMatrix aStack, TReal32 aMatrix[16])
    {
    if (aStack == EHuiGcMatrixModel)
        {
        const VGfloat m[9] = 
            {
            aMatrix[0], aMatrix[1], aMatrix[2],
            aMatrix[4], aMatrix[5], aMatrix[6],
            aMatrix[8], aMatrix[9], aMatrix[10],
            };
        vgMultMatrix(m);
        HUI_VG_INVARIANT();
        }
    }


void CHuiVg10Gc::Translate(THuiGcMatrix aMatrix,
                           TReal32 aX, TReal32 aY, TReal32 /*aZ*/) __SOFTFP
    {
    if (aMatrix == EHuiGcMatrixModel)
        {
        vgTranslate(aX, aY);
        HUI_VG_INVARIANT();
        }
    }


void CHuiVg10Gc::Scale(THuiGcMatrix aMatrix,
                         TReal32 aX, TReal32 aY, TReal32 /*aZ*/) __SOFTFP
    {
    if (aMatrix == EHuiGcMatrixModel)
        {
        vgScale(aX, aY);
        HUI_VG_INVARIANT();
        }
    }

void CHuiVg10Gc::Shear(THuiGcMatrix aMatrix,
                       TReal32 aX, TReal32 aY, TReal32 /*aZ*/) __SOFTFP
    {
    if (aMatrix == EHuiGcMatrixModel)
        {
        vgShear(aX, aY);
        HUI_VG_INVARIANT();
        }
    }

void CHuiVg10Gc::Rotate(THuiGcMatrix aMatrix, TReal32 aAngle,
                        TReal32 aX, TReal32 aY, TReal32 aZ) __SOFTFP
    {
    if (aMatrix != EHuiGcMatrixModel)
        {
        return;
        }

    // Only rotation around the unit Z axis is supported
	if (aX != 0.0f || aY != 0.0f || Abs(aZ) != 1.0f)
	    {
	    return;
	    }
		
    if (aZ < 0)
        {
        aAngle = -aAngle;
        }
    
    iMatrixFlags |= EMatrixFlagsRotation;
    vgRotate(aAngle);
    HUI_VG_INVARIANT();
    }


// Replicate the current OpenVG matrix to the matrix stack
void CHuiVg10Gc::UpdateMatrix(VGMatrixMode aMatrix)
    {
    VGfloat m[9];
    ASSERT(vgGeti(VG_MATRIX_MODE) == VG_MATRIX_IMAGE_USER_TO_SURFACE);
    vgGetMatrix(m);
    vgSeti(VG_MATRIX_MODE, aMatrix);
    vgLoadMatrix(m);
    vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
        
    HUI_VG_INVARIANT();
    }

void CHuiVg10Gc::UpdateClientMatrix()
    {
    // Replicate the current OpenVG matrix to the matrix stack
    vgGetMatrix((VGfloat*)iMatrixStack->Current().iMatrix);
    
    // The matrix is *probably* not an identity transform
    iMatrixStack->Current().iIsIdentity = EFalse;
    HUI_VG_INVARIANT();
    }

void CHuiVg10Gc::CreateVgObjectsL()
    {
    // Make sure we have enough resources to work with
    ASSERT(vgGeti(VG_MAX_SCISSOR_RECTS) >= 1);
    
    // Create the default VG objects
    iPath = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 
                         5, 8, VG_PATH_CAPABILITY_APPEND_TO);
    iImagePath = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 
                              5, 8, VG_PATH_CAPABILITY_APPEND_TO | VG_PATH_CAPABILITY_MODIFY);
    iArcPath = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 
                            2, 7, VG_PATH_CAPABILITY_APPEND_TO);
    iPaint = vgCreatePaint();
    iPaintColor = 0;
    vgSetColor(iPaint, iPaintColor);
    iGradientPaint = vgCreatePaint();
    iBlendMode = VG_BLEND_SRC_OVER;

    // Initialize a rectangle path with dummy coordinates
    iRectPath = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 
                             5, 8, VG_PATH_CAPABILITY_APPEND_TO | VG_PATH_CAPABILITY_MODIFY);

    iRoundRectPath = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 
                                 5, 8, VG_PATH_CAPABILITY_APPEND_TO | VG_PATH_CAPABILITY_MODIFY);

    iEllipsePath = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 
                                 5, 8, VG_PATH_CAPABILITY_APPEND_TO | VG_PATH_CAPABILITY_MODIFY);
    
    const VGubyte rectSegments[] =
        {
        VG_MOVE_TO_ABS,
        VG_LINE_TO_REL,
        VG_LINE_TO_REL,
        VG_LINE_TO_REL,
        VG_CLOSE_PATH
        };
    const VGfloat rectCoords[] = 
        {
         0.0f, 0.0f,             // (x, y)
         1.0f, 0.0f,             // (width, 0)
         0.0f, 1.0f,             // (0, height)
        -1.0f, 0.0f,             // (-width, 0)
        };
    vgAppendPathData(iRectPath, 5, rectSegments, rectCoords);
    vgRemovePathCapabilities(iRectPath, VG_PATH_CAPABILITY_APPEND_TO);
    vgAppendPathData(iImagePath, 5, rectSegments, rectCoords);
    vgRemovePathCapabilities(iImagePath, VG_PATH_CAPABILITY_APPEND_TO);

    // Initialize a line path with dummy coordinates
    iLinePath = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 
                             2, 4, VG_PATH_CAPABILITY_APPEND_TO | VG_PATH_CAPABILITY_MODIFY);
    const VGubyte lineSegments[] =
        {
        VG_MOVE_TO_ABS,
        VG_LINE_TO_ABS,
        };
    const VGfloat lineCoords[] = 
        {
        0.0f, 0.0f,             // (x, y)
        1.0f, 1.0f,             // (x, y)
        };
    vgAppendPathData(iLinePath, 2, lineSegments, lineCoords);
    vgRemovePathCapabilities(iLinePath, VG_PATH_CAPABILITY_APPEND_TO);
    
    // Initialize a path for drawing borders
    iBorderPath = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 
                               11, 10 * 2, VG_PATH_CAPABILITY_APPEND_TO | VG_PATH_CAPABILITY_MODIFY);

    const VGubyte borderSegments[12] =
        {
        VG_MOVE_TO_ABS,
        VG_LINE_TO_REL,
        VG_LINE_TO_REL,
        VG_LINE_TO_REL,
        VG_LINE_TO_REL,
        VG_LINE_TO_REL,
        VG_LINE_TO_REL,
        VG_LINE_TO_REL,
        VG_LINE_TO_REL,
        VG_LINE_TO_REL,
        VG_LINE_TO_REL,
        VG_CLOSE_PATH,
        };

    const VGfloat borderCoords[10 * 2] = 
        {
        0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
        };

    vgAppendPathData(iBorderPath, 12, borderSegments, borderCoords);
    vgRemovePathCapabilities(iBorderPath, VG_PATH_CAPABILITY_APPEND_TO);
        
    // Get hardware configuration
    CHuiVg10RenderPlugin& renderer = (CHuiVg10RenderPlugin&) CHuiStatic::Renderer();
    TInt hwConf = renderer.GetHwConfigurationFlags();
    
    if ( hwConf & KHuiAntialiasing )
        {
        SetQuality( EHuiQualityAccurate );
        }
    else
        {
        SetQuality( EHuiQualityFast );
        }
    
    iVgObjectsCreated = ETrue;
    }

void CHuiVg10Gc::InitState()
    {
    // Clean matrix stack in case there is anything left
    // We can't construct a new stack here because we are not allowed to leave.
    // We keep the original stack and just delete the contents leaving one 
    // identity matrix that is always added when a new matrix stack is created
    TInt i = 0;
    // One identity matrix will remain.
    // When a new matrix stack is created, one identity matrix is added
    // It can never be removed, the code would panic.
    for ( i = 0; i < iMatrixStack->Count() - 2; i++ )
        {
        iMatrixStack->Pop(); 
        }
    // remove flags from stack, too.
    iMatrixFlagsStack.Reset();

    iScissorRect = TRect(0, 0, 0, 0);
    iMatrixFlags = 0;
    
    if (!iVgObjectsCreated)
        {
        TRAP_IGNORE(CreateVgObjectsL());    
        }

    // Default paint
    vgSetParameteri(iPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
    vgSetPaint(iPaint, VG_FILL_PATH | VG_STROKE_PATH);
        
    // Gradient paint
    vgSetParameteri(iGradientPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT);
        
    HUI_VG_INVARIANT();
    
    // Reset default state
    
    Enable(EFeatureBlending);
    Disable(EFeatureDepthTest);
	iStateScissorTest = ETrue;    
    Disable(EFeatureClipping);

    // Use the image matrix as the primary matrix
    vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);

    RestoreState();
    HUI_VG_INVARIANT();
    }

void CHuiVg10Gc::SetQuality(THuiQuality aQuality)
    {
    CHuiGc::SetQuality(aQuality);
    switch (Quality())
        {
        case EHuiQualityAccurate:
            vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_BETTER);
            vgSeti(VG_IMAGE_QUALITY, VG_IMAGE_QUALITY_BETTER);
            break;
        case EHuiQualityFast:
            vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_FASTER);
            vgSeti(VG_IMAGE_QUALITY, VG_IMAGE_QUALITY_FASTER);
            break;
        default:
            break;
        }
    HUI_VG_INVARIANT();
    }

void CHuiVg10Gc::SetFillRule( THuiFillMode aFillMode )
    {   
    switch (aFillMode)
       {
       case EHuiFillNonZero:
           vgSeti(VG_FILL_RULE, VG_NON_ZERO);
           break;
       case EHuiFillEvenOdd:
           vgSeti(VG_FILL_RULE, VG_EVEN_ODD);
           break;
       default:
           break;
       }
    HUI_VG_INVARIANT();   
    }

void CHuiVg10Gc::RestoreState() const
    {
    // Restore paint
    vgSetPaint(iPaint, VG_FILL_PATH | VG_STROKE_PATH);        

    // Restore scissor test state
    if(iStateScissorTest)
        {
        vgSeti(VG_SCISSORING, VG_TRUE);
        }
    else
        {
        vgSeti(VG_SCISSORING, VG_FALSE);
        }
    
    // Restore scissor rects
    // This fixes CHuiFxEffect cached draw
    TInt count = iClipRegion.Count();
    VGint coords[KHuiMaxVgScissorRects * 4];

    if(count > KHuiMaxVgScissorRects)
        {
        count = KHuiMaxVgScissorRects; //only 32 scissor rects supported    
        }
        
    TInt numberOfCoords = count*4;
    for ( TInt i = 0, j=0 ; i < numberOfCoords ; j++)
        { 
        coords[i++] = iClipRegion[j].iTl.iX;
        coords[i++] = iClipRegion[j].iTl.iY;
        coords[i++] = iClipRegion[j].Width();
        coords[i++] = iClipRegion[j].Height();      
        }
    
    vgSetiv(VG_SCISSOR_RECTS, numberOfCoords, coords);          

    HUI_VG_INVARIANT();
    }

void CHuiVg10Gc::RestoreFlaggedState() const
    {
    // Get the changed stateflags from the renderplugin
    CHuiVg10RenderPlugin& renderer = (CHuiVg10RenderPlugin&) CHuiStatic::Renderer();
    TInt flags = renderer.GetRestoreStateFlags();
    
    // First a quick check, if nothing needs to be done
    if(!flags)
        {
        return;
        }
      
    // Check each flag and act accrodingly!
    if(flags & EHuiVg10GcStateFlagDirtyPaint)
        {
        // Restore paint
        vgSetPaint(iPaint, VG_FILL_PATH | VG_STROKE_PATH);
        }

    if(flags & EHuiVg10GcStateFlagDirtyScissor)
        {
        // Restore scissor test state
        if(iStateScissorTest)
            {
            vgSeti(VG_SCISSORING, VG_TRUE);
            }
        else
            {
            vgSeti(VG_SCISSORING, VG_FALSE);
            }
        }
    
    if(flags & EHuiVg10GcStateFlagDirtyScissorRects)
        {
        // Restore scissor rects
        TInt count = iClipRegion.Count();
        VGint coords[KHuiMaxVgScissorRects * 4];

        if(count > KHuiMaxVgScissorRects)
            {
            count = KHuiMaxVgScissorRects; //only 32 scissor rects supported    
            }
            
        TInt numberOfCoords = count*4;
        for ( TInt i = 0, j=0 ; i < numberOfCoords ; j++)
            { 
            coords[i++] = iClipRegion[j].iTl.iX;
            coords[i++] = iClipRegion[j].iTl.iY;
            coords[i++] = iClipRegion[j].Width();
            coords[i++] = iClipRegion[j].Height();      
            }
        
        vgSetiv(VG_SCISSOR_RECTS, numberOfCoords, coords);
        }

    // Clear the flags!
    renderer.ClearRestoreStateFlags();
    
    HUI_VG_INVARIANT();
    }

void CHuiVg10Gc::UpdateProjection()
    {
    // Nothing to do
    }


TInt CHuiVg10Gc::TextureUnits() const
    {
    return 1;
    }


void CHuiVg10Gc::SetTextureUnits(TInt /*aTextureUnitCount*/)
    {
    // Nothing to do
    }


void CHuiVg10Gc::Enable(TFeature aFeature, TBool aDoEnable)
    {
    HUI_VG_INVARIANT();

    switch(aFeature)
        {
        case EFeatureDepthTest:
            // Not supported
            break;

        case EFeatureDepthWrite:
            // Not supported
            break;

        case EFeatureTexturing:
            // Always enabled
            break;

        case EFeatureBlending:
            if(aDoEnable)
                {
                vgSeti(VG_BLEND_MODE, iBlendMode);
                }
            else
                {
                vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);
                }
            break;

        case EFeatureClipping:
            if(aDoEnable)
                {
                // enable clipping
                //if(!iStateScissorTest)
                	{
                	iStateScissorTest = ETrue;
                    vgSeti(VG_SCISSORING, VG_TRUE);
                	}
                }
            else
                {
                // disable clipping
                //if(iStateScissorTest)
                	{
                	iStateScissorTest = EFalse;
                    vgSeti(VG_SCISSORING, VG_FALSE);
                	}
                
                }
            break;

        case EFeatureAntialias:
            if(aDoEnable)
                {
                vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_BETTER);
                }
            else
                {
                vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_FASTER);
                }
            break;

        case EFeatureFog:
            // Not supported
            break;

        default:
            break;
        }

    HUI_VG_INVARIANT();
    }


void CHuiVg10Gc::SetBlendMode(TBlendMode aBlendMode)
    {
    switch(aBlendMode)
        {
        case EBlendAdd:
            iBlendMode = VG_BLEND_ADDITIVE;
            break;

        default:
            iBlendMode = VG_BLEND_SRC_OVER;
            break;
        }
        vgSeti(VG_BLEND_MODE, iBlendMode);
    }


void CHuiVg10Gc::SetTextureMode(TTextureMode aTextureMode, TReal32 /*aParam*/) __SOFTFP
    {
    switch(aTextureMode)
        {
        case ETextureModeNormal:
            break;

        default:
            break;
        }

    HUI_VG_INVARIANT();
    }


void CHuiVg10Gc::SetDimmingFog(const TRgb& /*aColor*/, TReal32 /*aAmount*/) __SOFTFP
    {
    // Fog not supported
    }

void CHuiVg10Gc::Clear(const TRect& aRect)
    {
    HUI_VG_INVARIANT();
    
    UpdateClientMatrix();

    THuiRealRect transformed = aRect;
    iMatrixStack->Current().Multiply(transformed.iTl);
    iMatrixStack->Current().Multiply(transformed.iBr);
        
    // Normalize the rectangle
    if (transformed.iTl.iX > transformed.iBr.iX)
        {
        TReal32 tmp = transformed.iTl.iX;
        transformed.iTl.iX = transformed.iBr.iX;
        transformed.iBr.iX = tmp;
        }
    if (transformed.iTl.iY > transformed.iBr.iY)
        {
        TReal32 tmp = transformed.iTl.iY;
        transformed.iTl.iY = transformed.iBr.iY;
        transformed.iBr.iY = tmp;
        }            
    VGfloat scale = 1.0f / 255.0f;
    VGfloat color[] = 
        {
        PenColor().Red()   * scale,
        PenColor().Green() * scale,
        PenColor().Blue()  * scale,
        PenAlpha() * scale
        };

    vgSetfv(VG_CLEAR_COLOR, 4, color);
    vgClear(transformed.iTl.iX, transformed.iTl.iY, transformed.Width(), transformed.Height());
    HUI_VG_INVARIANT();
    }

void CHuiVg10Gc::Clear()
    {
    HUI_VG_INVARIANT();
    TInt x = ProjectionViewport().iTl.iX;
    TInt y = ProjectionViewport().iTl.iY;
    TInt w = ProjectionViewport().Width();
    TInt h = ProjectionViewport().Height();
    VGfloat scale = 1.0f / 255.0f;
    VGfloat color[] = 
        {
        PenColor().Red()   * scale,
        PenColor().Green() * scale,
        PenColor().Blue()  * scale,
        PenAlpha() * scale
        };
    vgSetfv(VG_CLEAR_COLOR, 4, color);
    vgClear(x, y, w, h);
    HUI_VG_INVARIANT();
    }

	
void CHuiVg10Gc::ClearDepth()
    {
    Clear();
    }


void CHuiVg10Gc::ClearColorAndDepth()
    {
    Clear();
    }

// Do renderer specific initializations of the frame
void CHuiVg10Gc::InitNewFrame()
	{
	LoadIdentity(EHuiGcMatrixModel);
	}

void CHuiVg10Gc::Clip(const TRect& aClipRect)
    {
    THuiRealRect transformed = aClipRect;
    
    HUI_DEBUGF4(_L("CHuiVg10Gc::Clip() - aClipRect     (%5i, %5i, %5i, %5i)"),
                aClipRect.iTl.iX, aClipRect.iTl.iY,
                aClipRect.iBr.iX, aClipRect.iBr.iY);
    
    // Transform the rectangle using our stacks
    UpdateClientMatrix();
    iMatrixStack->Current().Multiply(transformed.iTl);
    iMatrixStack->Current().Multiply(transformed.iBr);
    
    // Normalize the rectangle
    if (transformed.iTl.iX > transformed.iBr.iX)
    	{
    	TReal32 tmp = transformed.iTl.iX;
    	transformed.iTl.iX = transformed.iBr.iX;
    	transformed.iBr.iX = tmp;
    	}
    if (transformed.iTl.iY > transformed.iBr.iY)
    	{
    	TReal32 tmp = transformed.iTl.iY;
    	transformed.iTl.iY = transformed.iBr.iY;
    	transformed.iBr.iY = tmp;
    	}

    HUI_DEBUGF4(_L("CHuiVg10Gc::Clip() - Transformed = (%5.0f, %5.0f, %5.0f, %5.0f)"),
                transformed.iTl.iX, transformed.iTl.iY,
                transformed.iBr.iX, transformed.iBr.iY);

    CHuiGc::Clip(transformed.Round());
    HUI_VG_INVARIANT();
    }


void CHuiVg10Gc::SetClip(const TRect& aClipRect)
    {
    iScissorRect = aClipRect;
    iScissorRect.Normalize();
    
    CHuiGc::SetClip(iScissorRect);

    VGint coords[4] = 
        {
        iScissorRect.iTl.iX,  iScissorRect.iTl.iY,
        iScissorRect.Width(), iScissorRect.Height()
        };
   
    Enable(EFeatureClipping);    
    vgSetiv(VG_SCISSOR_RECTS, 4, coords);
    HUI_VG_INVARIANT();
    }

void CHuiVg10Gc::Clip(const TRegion& aRegion)
    {
    UpdateClientMatrix();

    iTempRegion.Clear();
    
    for (TInt i=0; i<aRegion.Count(); i++)
        {
        THuiRealRect transformed = aRegion[i];
        iMatrixStack->Current().Multiply(transformed.iTl);
        iMatrixStack->Current().Multiply(transformed.iBr);
        
        // Normalize the rectangle
        if (transformed.iTl.iX > transformed.iBr.iX)
        	{
        	TReal32 tmp = transformed.iTl.iX;
        	transformed.iTl.iX = transformed.iBr.iX;
        	transformed.iBr.iX = tmp;
        	}
        if (transformed.iTl.iY > transformed.iBr.iY)
        	{
        	TReal32 tmp = transformed.iTl.iY;
        	transformed.iTl.iY = transformed.iBr.iY;
        	transformed.iBr.iY = tmp;
        	}            
        
        iTempRegion.AddRect(transformed.Round());
        }
	    
	CHuiGc::Clip(iTempRegion);	    
    
    HUI_VG_INVARIANT();
    }
    
void CHuiVg10Gc::SetClipRegion(const TRegion& aRegion)
    {
    TInt count = aRegion.Count();
    VGint coords[KHuiMaxVgScissorRects * 4];

    if(count > KHuiMaxVgScissorRects)
        {
        count = KHuiMaxVgScissorRects; //only 32 scissor rects supported    
        }
        
    TInt numberOfCoords = count*4;
    for ( TInt i = 0, j=0 ; i < numberOfCoords ; j++)
        { 
        coords[i++] = aRegion[j].iTl.iX;
        coords[i++] = aRegion[j].iTl.iY;
        coords[i++] = aRegion[j].Width();
        coords[i++] = aRegion[j].Height();      
        }
    
    CHuiGc::SetClipRegion(aRegion);     
    
    Enable(EFeatureClipping);    
    vgSetiv(VG_SCISSOR_RECTS, numberOfCoords, coords);          
    
    HUI_VG_INVARIANT();
    }

void CHuiVg10Gc::CancelClipping()
    {
    Disable(EFeatureClipping);    
    }

void CHuiVg10Gc::DrawText(const CHuiTextMesh& aTextMesh,
                          const THuiRealRect& aBounds,
                          TReal32 aShadow) __SOFTFP
    {
    CHuiGc::DrawText(aTextMesh, aBounds, aShadow);
    }


/**
 *  Given a THuiImage, return the corresponding VGImage or 
 *  VG_INVALID_HANDLE if there is none.
 */
static VGImage GetVGImageFromTexture(const MHuiSegmentedTexture& aTexture)
    {
    if (aTexture.SegmentCount() == 1)
        {
        return (VGImage)aTexture.SegmentName(0);
        }
    return VG_INVALID_HANDLE;
    }


/**
 *  Construct a source rectangle based on the texture coordinates
 *  specified for an image.
 */
static THuiRealRect GetSourceRectangleFromImage(const THuiImage& aImage)
    {
    TReal32 texCoords[8];
    aImage.GetTexCoords(texCoords);
    THuiRealRect sourceRect;
    
    sourceRect.iTl.iX = texCoords[0];
    sourceRect.iTl.iY = texCoords[1];
    sourceRect.iBr.iX = texCoords[4];
    sourceRect.iBr.iY = texCoords[5];
    
    return sourceRect;
    }

void CHuiVg10Gc::DoDrawImage(const THuiImage& aImage,
                             const THuiRealPoint& aTopLeft,
                             const THuiRealSize& aSize)
    {
    if(!aImage.HasTexture())
        {
        return;
        }
    
    // Fetch the texture coordinates from the image
    THuiRealRect destRect(aTopLeft, aSize);
    THuiRealRect sourceRect(GetSourceRectangleFromImage(aImage));
    DrawTexture(aImage.Texture(), sourceRect, destRect);
    }


void CHuiVg10Gc::DoDrawImages(const THuiImage& aImage,
                                const THuiImage& aImage2,
                                const THuiRealPoint& aTopLeft,
                                const THuiRealSize& aSize)
    {
    DoDrawImage(aImage,  aTopLeft, aSize);
    DoDrawImage(aImage2, aTopLeft, aSize);
    }


void CHuiVg10Gc::UpdateColor(TReal32 /*aAlphaFactor*/) __SOFTFP
    {
    VGuint color = (PenColor().Internal() << 8) | PenAlpha();
    
#if defined(RENDER_DEBUG_RECTANGLES)
    color = Math::Random() | 0xff;
#endif
    
    // Update the color of the current paint
    // if required
    if (iPaintColor != color)
        {
        vgSetColor(iPaint, color);
        iPaintColor = color;
        }
    
    // Detect white fully opaque color
    if (color == 0xffffffff)
        {
        vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
        }
    else
        {
        vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_MULTIPLY);
        }
    HUI_VG_INVARIANT();
    }

void CHuiVg10Gc::DrawCroppedTexture(const MHuiSegmentedTexture& aTexture, const THuiRealRect& aSourceRect,
                                    const THuiRealRect& aDestRect)
    {
    // Render state which affects what we do here (roughly decreasing order of probability):
    // - Source cropping
    // - Color modulation
    // - Alpha modulation
    // - Affine matrix transform (i.e. other than scale or translation)
    //
    // Difficult combinations:
    // - Source cropping with color or alpha modulation
    //   - Option 1: Create a child image from the cropped region
    //     - Can't do this because the cropping region is in floating point coords.
    //     - Performance overhead possibly non-negligible.
    //   - Option 2: Use scissoring to do the cropping
    //     - Does not work for rotate/skew transform.
    //   - Option 3: Use a mask to do the cropping
    //     - Auxiliary mask bitmap needed, possible performance hit.
    //   - Option 4: Use a pattern paint
    //     - Color/alpha modulation requires an offscreen image.
    // - Resolution: Go with option 2 and option 1 if rotation/skewing is in effect.
    TSize imageSize = aTexture.Size();
    VGfloat srcW   = aSourceRect.Width()  * imageSize.iWidth;
    VGfloat srcH   = aSourceRect.Height() * imageSize.iHeight;
    VGfloat srcX   = aSourceRect.iTl.iX   * imageSize.iWidth;
    VGfloat srcY   = aSourceRect.iTl.iY   * imageSize.iHeight;

    // Make sure the source rectangle is not degenerate
    srcW = Max(1.0f, srcW);
    srcH = Max(1.0f, srcH);
    
    VGfloat scaleX = aDestRect.Width()  / srcW;
    VGfloat scaleY = aDestRect.Height() / srcH;
    VGImage image = VG_INVALID_HANDLE;
    
	// Check if OpenVg state has changed
    RestoreFlaggedState();
    
#ifdef __NVG
    const CHuiVg10Texture& texture = static_cast<const CHuiVg10Texture&>( aTexture );
    TBool isExtended = texture.IsExtended();
#endif
    
    // Getting the vgImage out of the texture
    image = GetVGImageFromTexture( aTexture );
    
    if (iMatrixFlags & EMatrixFlagsRotation)
        {
        VGImage tmpImage = vgChildImage(image, (VGint)srcX, imageSize.iHeight - (VGint)srcY - (VGint)srcH, (VGint)srcW, (VGint)srcH);
        
        if (tmpImage == VG_INVALID_HANDLE)
            {
            HUI_DEBUG(_L("CHuiVg10Gc::DrawCroppedTexture() - Unable to create temporary child image."));
            // We cannot leave because we are called by a non-leaving exported function
            // If we cannot draw, we just return without doing anything.
            return;
            }
        HUI_VG_INVARIANT();
        
        // Render the child image
        Push(EHuiGcMatrixModel);
#if !defined(RENDER_DEBUG_RECTANGLES)
        vgTranslate(aDestRect.iTl.iX, aDestRect.iTl.iY);
        vgScale(scaleX, scaleY);
        vgDrawImage(tmpImage);
#else
        TRect d(aDestRect.iTl.iX, aDestRect.iTl.iY, aDestRect.iBr.iX, aDestRect.iBr.iY);
        DrawRect(d);
#endif
        Pop(EHuiGcMatrixModel);
        
        vgDestroyImage(tmpImage);
        HUI_VG_INVARIANT();
        return;
        }
    
    // Set a scissor rectangle that corresponds with the target rectangle
    TBool clippingWasEnabled = iStateScissorTest;
    
    if (!clippingWasEnabled)
        {
        Enable(EFeatureClipping);    
        }
    
    PushClip();
    Clip(aDestRect);    
    
    // Render the image
    Push(EHuiGcMatrixModel);
#if !defined(RENDER_DEBUG_RECTANGLES)
    vgTranslate(aDestRect.iTl.iX, aDestRect.iTl.iY);
    vgScale(scaleX, scaleY);
    vgTranslate(-srcX, -srcY);

#ifdef __NVG
    if ( isExtended )
        {
        // Determine the size to which we want to draw the NVG icon paths
        TSize contentSize( HUI_ROUND_FLOAT_TO_INT(aDestRect.Width()),
                HUI_ROUND_FLOAT_TO_INT(aDestRect.Height()) );
        UpdateMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
        // Draw the NVG data (be it either the object cached commands or the "normal" nvg data)
        DrawNVG(texture.GetExtendedTextureData(), texture.GetIconCommandsData(), contentSize, EFalse);
        }
    else
        {
        if (image != VG_INVALID_HANDLE)
            {
            //HUI_DEBUG1(_L("HuiVg10Gc::DrawCroppedTexture - drawing with vgDrawImage(%d) instead of DrawNVG"), image);
            vgDrawImage(image);
            }
        else
            {
            HUI_DEBUG1(_L("HuiVg10Gc::DrawCroppedTexture - INVALID HANDLE, vgDrawImage() not called!"), image);
            }
        }
#else
    vgDrawImage(image);
#endif // __NVG

#else // RENDER_DEBUG_RECTANGLES
    TRect d(aDestRect.iTl.iX, aDestRect.iTl.iY, aDestRect.iBr.iX, aDestRect.iBr.iY);
    DrawRect(d);
#endif
    HUI_VG_INVARIANT();
    Pop(EHuiGcMatrixModel);
    
    // Restore state
    PopClip();

    if (!clippingWasEnabled)
        {
        Disable(EFeatureClipping);    
        }
    
    HUI_VG_INVARIANT();
    
#if 0
    // Crop implementation using a paint pattern
    // TODO: Handle color modulation + cropping
    VGfloat srcW   = aSourceRect.Width()  * aImage.Texture().Size().iWidth;
    VGfloat srcH   = aSourceRect.Height() * aImage.Texture().Size().iHeight;
    VGfloat srcX   = aSourceRect.iTl.iX   * aImage.Texture().Size().iWidth;
    VGfloat srcY   = aSourceRect.iTl.iY   * aImage.Texture().Size().iHeight;
    VGfloat scaleX = aDestRect.Width()  / srcW;
    VGfloat scaleY = aDestRect.Height() / srcH;
    VGImage image  = GetVGImageFromTexture(aTexture);

    vgPaintPattern(iPaint, image);
    
    // Transform the paint pattern to fill the destination rectangle as required
    vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER);
    vgLoadIdentity();
    vgTranslate(aDestRect.iTl.iX, aDestRect.iTl.iY);
    vgScale(scaleX, scaleY);
    vgTranslate(-srcX, -srcY);
    vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
    
    // Update the path transformation matrix
    UpdateMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);

    // Draw a rectangle which is filled with the image as a pattern
    const VGfloat coords[] = 
        {
        aDestRect.iTl.iX, aDestRect.iTl.iY,
        aDestRect.Width(), 0,
        0, aDestRect.Height(),
        -aDestRect.Width(), 0,
        };
    vgModifyPathCoords(iImagePath, 0, 5, coords);
    vgDrawPath(iImagePath, VG_FILL_PATH);
    
    // Restore the state
    vgPaintPattern(iPaint, VG_INVALID_HANDLE);
    UpdateColor();
    vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER);
    vgLoadIdentity();
    vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
    HUI_VG_INVARIANT();
#endif
    }

void CHuiVg10Gc::DrawTexture(const MHuiSegmentedTexture& aTexture, 
                             const THuiRealRect& aSourceRect, 
                             const THuiRealRect& aDestRect)
    {
    // See if the image is cropped
    const VGfloat epsilon = 1e-3;
    if (aSourceRect.iTl.iX > epsilon || 
        aSourceRect.iTl.iY > epsilon ||
        aSourceRect.iBr.iX < 1.0f - epsilon ||
        aSourceRect.iBr.iY < 1.0f - epsilon)
        {
        DrawCroppedTexture(aTexture, aSourceRect, aDestRect);
        return;
        }

	// Check if OpenVg state has changed
    RestoreFlaggedState();
    
    Push(EHuiGcMatrixModel);
#if !defined(RENDER_DEBUG_RECTANGLES)
    vgTranslate(aDestRect.iTl.iX, aDestRect.iTl.iY);
    
#ifdef __NVG
    const CHuiVg10Texture& texture = static_cast<const CHuiVg10Texture&>( aTexture );
    TBool isExtended = texture.IsExtended();
    
    if (isExtended)
        {
        UpdateMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
        TSize contentSize(0, 0);
        contentSize.SetSize( HUI_ROUND_FLOAT_TO_INT( aDestRect.Width() ),
            HUI_ROUND_FLOAT_TO_INT( aDestRect.Height() ) );
        // Draw the NVG data (be it either the object cached commands or the "normal" nvg data)
        DrawNVG(texture.GetExtendedTextureData(), texture.GetIconCommandsData(), contentSize, EFalse);
        }
    else
        {
        // "Option C" -way
        VGfloat scaleX = aDestRect.Width()  / aTexture.Size().iWidth;
        VGfloat scaleY = aDestRect.Height() / aTexture.Size().iHeight;
        VGImage image = GetVGImageFromTexture( aTexture );

        if (image != VG_INVALID_HANDLE)
            {
            vgScale(scaleX, scaleY);
            vgDrawImage(image);
            //HUI_DEBUG1(_L("HuiVg10Gc::DrawTexture - vgDrawImage(%d) drawn!"), image);
            }
        else
            {
            HUI_DEBUG(_L("HuiVg10Gc::DrawTexture - INVALID HANDLE, vgDrawImage() not called!"));
            }
        }
#else
    // TODO: Fast paths for unit scale and opaque blending
    VGfloat scaleX = aDestRect.Width()  / aTexture.Size().iWidth;
    VGfloat scaleY = aDestRect.Height() / aTexture.Size().iHeight;
    VGImage image = GetVGImageFromTexture(aTexture);
    
    vgScale(scaleX, scaleY);
    vgDrawImage(image);
#endif // __NVG
    
#else
    TRect d(aDestRect.iTl.iX, aDestRect.iTl.iY, aDestRect.iBr.iX, aDestRect.iBr.iY);
    DrawRect(d);
#endif

    HUI_VG_INVARIANT();
    Pop(EHuiGcMatrixModel);
    }

void CHuiVg10Gc::DrawStretchImage(TStretchMode aMode,
                                  const THuiImage& aImage, 
                                  const THuiRealRect& aRect,
                                  TInt aStartWidth, 
                                  TInt aEndWidth)
    {
    if (!aImage.HasTexture())
        {
        return;
        }

    UpdateColor();

    THuiRealPoint aTopLeft(aRect.iTl);
    THuiRealSize  aSize(aRect.iBr.iX - aRect.iTl.iX, aRect.iBr.iY - aRect.iTl.iY);
    THuiRealRect sourceRect(GetSourceRectangleFromImage(aImage));
    THuiRealSize imageSize = aImage.Texture().Size();
    
	switch(aMode) 
		{
	    case EStretchFull:
			{
			DrawTexture(aImage.Texture(), sourceRect, aRect);
	    	break;
			}
				    
	    case EStretchVertical:
	        {
            THuiRealRect destRect(aRect);
            if (aStartWidth > 0)
                {
                THuiRealRect edgeDestRect(aRect);
                THuiRealRect edgeSourceRect(sourceRect);
                edgeDestRect.iBr.iY   = edgeDestRect.iTl.iY   + aStartWidth;
                edgeSourceRect.iBr.iY = edgeSourceRect.iTl.iY + aStartWidth / imageSize.iHeight;
                DrawTexture(aImage.Texture(), edgeSourceRect, edgeDestRect);
                destRect.iTl.iY   += aStartWidth;
                sourceRect.iTl.iY += aStartWidth / imageSize.iHeight;
                }
            if (aEndWidth > 0)
                {
                THuiRealRect edgeDestRect(aRect);
                THuiRealRect edgeSourceRect(sourceRect);
                edgeDestRect.iTl.iY   = edgeDestRect.iBr.iY   - aEndWidth;
                edgeSourceRect.iTl.iY = edgeSourceRect.iBr.iY - aEndWidth / imageSize.iHeight;
                DrawTexture(aImage.Texture(), edgeSourceRect, edgeDestRect);
                destRect.iBr.iY   -= aEndWidth;
                sourceRect.iBr.iY -= aEndWidth / imageSize.iHeight;
                }
            DrawTexture(aImage.Texture(), sourceRect, destRect);
	        break;
	        }
	    case EStretchHorizontal:
	        {
            THuiRealRect destRect(aRect);
            if (aStartWidth > 0)
                {
                THuiRealRect edgeDestRect(aRect);
                THuiRealRect edgeSourceRect(sourceRect);
                edgeDestRect.iBr.iX   = edgeDestRect.iTl.iX   + aStartWidth;
                edgeSourceRect.iBr.iX = edgeSourceRect.iTl.iX + aStartWidth / imageSize.iWidth;
                DrawTexture(aImage.Texture(), edgeSourceRect, edgeDestRect);
                destRect.iTl.iX   += aStartWidth;
                sourceRect.iTl.iX += aStartWidth / imageSize.iWidth;
                }
            if (aEndWidth > 0)
                {
                THuiRealRect edgeDestRect(aRect);
                THuiRealRect edgeSourceRect(sourceRect);
                edgeDestRect.iTl.iX   = edgeDestRect.iBr.iX   - aEndWidth;
                edgeSourceRect.iTl.iX = edgeSourceRect.iBr.iX - aEndWidth / imageSize.iWidth;
                DrawTexture(aImage.Texture(), edgeSourceRect, edgeDestRect);
                destRect.iBr.iX   -= aEndWidth;
                sourceRect.iBr.iX -= aEndWidth / imageSize.iWidth;
                }
            DrawTexture(aImage.Texture(), sourceRect, destRect);
	        break;
	        }
	
	    default:
	        HUI_DEBUG(_L("CHuiVg10Gc::DrawStretchImage() - ERROR! Tried to use stretch mode that hasn't been implemented. Panicing."));
		    HUI_PANIC(THuiPanic::ENotImplemented);
	}
    
    HUI_VG_INVARIANT();
    }

void CHuiVg10Gc::DrawRect(const TRect& aRect)
    {
    if (iPaintPattern)
        {        
        // Add 0.5 to all coordinates to get them in the middle of pixels 
        TRect rect = aRect;
        rect.iTl.iX += 0.5f;
        rect.iTl.iY += 0.5f;
        rect.iBr.iX -= 0.5f;
        rect.iBr.iY -= 0.5f;
        
        const VGfloat coords[] = {
                rect.iTl.iX + 0.5f, rect.iTl.iY + 0.5f,
                rect.Width(), 0.0f,
                0.0f, rect.Height(),
                -rect.Width(), 0.0f,
            };

        UpdateColor();
        UpdateMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
        
        UsePaintPattern();
        
        vgModifyPathCoords(iRectPath, 0, 4, coords);
        vgDrawPath(iRectPath, VG_FILL_PATH);
        
        // Restore rect path
        const VGfloat rectCoords[] = 
            {
             0.0f, 0.0f,             // (x, y)
             1.0f, 0.0f,             // (width, 0)
             0.0f, 1.0f,             // (0, height)
            -1.0f, 0.0f,             // (-width, 0)
            };

        vgModifyPathCoords(iRectPath, 0, 4, rectCoords);        

        DiscardPaintPattern();
        }
    else
        {
        // fast path (doen not work with patterned fill)
        UpdateColor();
        UpdateMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
        vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
    
        vgTranslate(aRect.iTl.iX, aRect.iTl.iY);
        vgScale(aRect.Width(),aRect.Height());
    
        vgDrawPath(iRectPath, VG_FILL_PATH);
    
        vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
        UpdateMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
        }

    HUI_VG_INVARIANT();
    }

void CHuiVg10Gc::DrawPolygon( RArray<THuiRealPoint>& aPoints )
    {
    
    // use the path intended for dynamic shapes
    // it has type float and can hold any number of segments
       
    TInt count = aPoints.Count();
    VGfloat* coords = NULL;
    coords = new VGfloat[count * 2];
    
    VGubyte* segments = NULL;
    segments = new VGubyte[count + 1];
    
    if ( !coords || !segments )
        {
        // ran out of memory, must just return
        delete[] coords;
        delete[] segments;
        return;
        }
    
    for( TInt i = 0; i < count; i++ )
    	{
	    coords[2 * i] = aPoints[i].iX;
	    coords[2 * i + 1] = aPoints[i].iY;
	    segments[i] = VG_LINE_TO_ABS;
    	}
    // fix the first segment into move instead of draw	
    segments[0] = VG_MOVE_TO_ABS;
    // the last segment closes the path to get a solid object
    segments[count] = VG_CLOSE_PATH;
    
    UpdateColor();
    UpdateMatrix( VG_MATRIX_PATH_USER_TO_SURFACE );
    
    UsePaintPattern(); 
    
    vgAppendPathData( iPath, count + 1, segments, coords);

    vgDrawPath( iPath, VG_FILL_PATH );
    vgClearPath( iPath, VG_PATH_CAPABILITY_APPEND_TO );

    DiscardPaintPattern();
    
    // don't leak memory
    delete[] coords;
    delete[] segments;
        
    HUI_VG_INVARIANT();

    }    

void CHuiVg10Gc::DrawLine(const TPoint& aStart,
                          const TPoint& aEnd,
                          const TInt aThickness)
    {

    // Add 0.5 to all coordinates to get them in the middle of pixels 
    const VGfloat coords[] = {
            aStart.iX + 0.5f, aStart.iY + 0.5f,
            aEnd.iX + 0.5f, aEnd.iY + 0.5f,
        };
    
    UpdateColor();
    UpdateMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
    
    vgModifyPathCoords(iLinePath, 0, 2, coords);
    vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_SQUARE);
    vgSeti(VG_STROKE_LINE_WIDTH, aThickness);
    vgDrawPath(iLinePath, VG_STROKE_PATH);
    HUI_VG_INVARIANT();
    }

void CHuiVg10Gc::DrawEllipse(const TRect& aRect, THuiFillMode aDrawMode, const TInt aThickness)
    {
    // Fix given destination rect to be in th middle of openvg pixels
    THuiRealRect destinationRect = aRect;
    destinationRect.iTl.iX += 0.5f;
    destinationRect.iTl.iY += 0.5f;
    destinationRect.iBr.iX -= 0.5f;
    destinationRect.iBr.iY -= 0.5f;
    
    VGfloat alpha = PenAlpha()/255.0f;
    vgClearPath(iEllipsePath, VG_PATH_CAPABILITY_APPEND_TO);
    
    VGfloat cx = (destinationRect.iTl.iX + destinationRect.iBr.iX) / 2.f; 
    VGfloat cy  = (destinationRect.iTl.iY + destinationRect.iBr.iY) / 2.f;
    VGfloat width = destinationRect.Width();
    VGfloat height = destinationRect.Height();
    
    vguEllipse(iEllipsePath, cx, cy, width, height);
   
    UpdateColor();
    UpdateMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
    
    TInt oldThickness = vgGeti(VG_STROKE_LINE_WIDTH);
    if(oldThickness != aThickness)
        {
        vgSeti(VG_STROKE_LINE_WIDTH, aThickness);
        }
    VGPaint paint;
    if (aDrawMode != EHuiNoFill)
        {
        paint = vgGetPaint(VG_FILL_PATH);
        }
     else
        {
        paint = vgGetPaint(VG_STROKE_PATH);
        }

    VGfloat color[4], modifiedColor[4];
    
    if (paint != VG_INVALID_HANDLE)
       {
       vgGetParameterfv(paint, VG_PAINT_COLOR, 4, color);
       if (color[3]!=alpha)
           {
           modifiedColor[0] = color[0];
           modifiedColor[1] = color[1];
           modifiedColor[2] = color[2];
           modifiedColor[3] = alpha;
           vgSetParameterfv(paint, VG_PAINT_COLOR, 4, modifiedColor);
           }
       else
           {
           // no reason to set back the old color. it is the same.
           paint = VG_INVALID_HANDLE; 
           }
       }

    UsePaintPattern();
    
    if (aDrawMode != EHuiNoFill)
        {
        vgDrawPath(iEllipsePath, VG_FILL_PATH);
        }
    else
        {
        vgDrawPath(iEllipsePath, VG_STROKE_PATH);
        }

    DiscardPaintPattern();
    
    if (paint != VG_INVALID_HANDLE)
        {
        vgSetParameterfv(paint, VG_PAINT_COLOR, 4, color);
        HUI_VG_INVARIANT();
        }
    if(oldThickness != aThickness)
        {
        vgSeti(VG_STROKE_LINE_WIDTH, oldThickness);
        }
    HUI_VG_INVARIANT();
    
    }

void CHuiVg10Gc::DrawArc(const TRect& aRect, THuiFillMode aDrawMode, const TInt aThickness, TReal32 aStart, TReal32 aEnd, TBool aIsPie) __SOFTFP
    {
    // Fix given destination rect to be in th middle of openvg pixels
    THuiRealRect destinationRect = aRect;
    destinationRect.iTl.iX += 0.5f;
    destinationRect.iTl.iY += 0.5f;
    destinationRect.iBr.iX -= 0.5f;
    destinationRect.iBr.iY -= 0.5f;
    
    VGfloat alpha = PenAlpha() / 255.f;
    vgClearPath(iArcPath, VG_PATH_CAPABILITY_APPEND_TO);
    
    VGfloat cx = (destinationRect.iTl.iX + destinationRect.iBr.iX) / 2.f; 
    VGfloat cy  = (destinationRect.iTl.iY + destinationRect.iBr.iY) / 2.f;
    VGfloat width = destinationRect.Width();
    VGfloat height = destinationRect.Height();
    
    VGUArcType arcType = aIsPie ? VGU_ARC_PIE : VGU_ARC_OPEN;

    // Ready to draw the arc. Note that in OpenVG, y axis points upwards. Anti-clockwise goes
    // is towards positive direction. The method CHuiVg10CanvasGc::DoDrawPieAndArc made sure that 
    // angleExtent is always positive.
    TReal32 angleExtent = aEnd - aStart;
    vguArc(iArcPath, cx, cy, width, height, aStart, angleExtent, arcType);
   
    UpdateColor();
    UpdateMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
    
    TInt oldThickness = vgGeti(VG_STROKE_LINE_WIDTH);
    if(oldThickness != aThickness)
        {
        vgSeti(VG_STROKE_LINE_WIDTH, aThickness);
        }
    VGPaint paint;
    if (aDrawMode != EHuiNoFill)
        {
        paint = vgGetPaint(VG_FILL_PATH);
        }
     else
        {
        paint = vgGetPaint(VG_STROKE_PATH);
        }

    VGfloat color[4], modifiedColor[4];
    
    if (paint != VG_INVALID_HANDLE)
       {
       vgGetParameterfv(paint, VG_PAINT_COLOR, 4, color);
       if (color[3]!=alpha) 
           {
           modifiedColor[0] = color[0];
           modifiedColor[1] = color[1];
           modifiedColor[2] = color[2];
           modifiedColor[3] = alpha;
           vgSetParameterfv(paint, VG_PAINT_COLOR, 4, modifiedColor);
           }
       else
           {
           // no reason to set back the old color. it is the same.
           paint = VG_INVALID_HANDLE; 
           }
       }

    UsePaintPattern();
    
    if (aDrawMode != EHuiNoFill)
        {
        vgDrawPath(iArcPath, VG_FILL_PATH);
        }
    else
        {
        vgDrawPath(iArcPath, VG_STROKE_PATH);
        }

    DiscardPaintPattern();
    
    // Restore old values
    if (paint != VG_INVALID_HANDLE)
        {
        vgSetParameterfv(paint, VG_PAINT_COLOR, 4, color);
        HUI_VG_INVARIANT();
        }
    if(oldThickness != aThickness)
        {
        vgSeti(VG_STROKE_LINE_WIDTH, oldThickness);
        }
    HUI_VG_INVARIANT();
    
    }

void CHuiVg10Gc::DrawRoundRect(const TRect& aDestinationRect, const THuiRealSize& aSize, THuiFillMode aDrawMode, const TInt aThickness)
    {
    // Fix given destination rect to be in th middle of openvg pixels
    THuiRealRect destinationRect = aDestinationRect;
    destinationRect.iTl.iX += 0.5f;
    destinationRect.iTl.iY += 0.5f;
    destinationRect.iBr.iX -= 0.5f;
    destinationRect.iBr.iY -= 0.5f;
    
    VGfloat alpha = PenAlpha();
    vgClearPath(iRoundRectPath, VG_PATH_CAPABILITY_APPEND_TO);
    vguRoundRect(iRoundRectPath, destinationRect.iTl.iX, destinationRect.iTl.iY, destinationRect.Width(), destinationRect.Height(), aSize.iWidth, aSize.iHeight);
   
    UpdateColor();
    UpdateMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
    
    TInt oldThickness = vgGeti(VG_STROKE_LINE_WIDTH);
    if(oldThickness != aThickness)
        {
        vgSeti(VG_STROKE_LINE_WIDTH, aThickness);
        }
    VGPaint paint;
    if (aDrawMode != EHuiNoFill)
        {
        paint = vgGetPaint(VG_FILL_PATH);
        }
     else
        {
        paint = vgGetPaint(VG_STROKE_PATH);
        }

    VGfloat color[4], modifiedColor[4];
    
    if (paint != VG_INVALID_HANDLE)
       {
       vgGetParameterfv(paint, VG_PAINT_COLOR, 4, color);
       if (color[3]!=alpha)
           {
           modifiedColor[0] = color[0];
           modifiedColor[1] = color[1];
           modifiedColor[2] = color[2];
           modifiedColor[3] = alpha;
           vgSetParameterfv(paint, VG_PAINT_COLOR, 4, modifiedColor);
           }
       else
           {
           // no reason to set back the old color. it is the same.
           paint = VG_INVALID_HANDLE; 
           }
       }

    UsePaintPattern();
    
    if (aDrawMode != EHuiNoFill)
        {
        vgDrawPath(iRoundRectPath, VG_FILL_PATH);
        }
    else
        {
        vgDrawPath(iRoundRectPath, VG_STROKE_PATH);
        }

    DiscardPaintPattern();
    
    if (paint != VG_INVALID_HANDLE)
        {
        vgSetParameterfv(paint, VG_PAINT_COLOR, 4, color);
        HUI_VG_INVARIANT();
        }
    if(oldThickness != aThickness)
        {
        vgSeti(VG_STROKE_LINE_WIDTH, oldThickness);
        }
    HUI_VG_INVARIANT();
    }

void CHuiVg10Gc::DrawBorders(const TRect& aOuterRect, 
				  TReal32 aLeftBorderWidth,
                  TReal32 aRightBorderWidth, 
				  TReal32 aTopBorderHeight,
                  TReal32 aBottomBorderHeight, 
                  TBorderMode aBorderMode,
                  const THuiImage* aImage) __SOFTFP
	{	
    UpdateColor();
    
    if (aBorderMode == EBorderImage)
        {
        TReal32 avgBorderWidth     = (aLeftBorderWidth + aRightBorderWidth) * .5f;
        TReal32 avgBorderHeight    = (aTopBorderHeight + aBottomBorderHeight) * .5f;
        THuiRealPoint borderOffset = THuiRealPoint((aRightBorderWidth   - aLeftBorderWidth) * .5f,
                                                   (aBottomBorderHeight - aTopBorderHeight) * .5f);
        DrawBorderImages(aOuterRect, avgBorderWidth, avgBorderHeight, borderOffset, aImage);
        }
    else if (aBorderMode == EBorderFixedCorners)
        {
        DrawBorderFixedCorners(aOuterRect, aLeftBorderWidth, aRightBorderWidth, 
                               aTopBorderHeight, aBottomBorderHeight, aImage);
        }
    else
        {
        // We cannot leave here because we are a non-leaving function,
        // and we cannot return an error either. 
        // If the caller gives us invalid parameters, we do nothing.
        return;
        }

    HUI_VG_INVARIANT();
	}

void CHuiVg10Gc::DrawBorderImages(const TRect& aOuterRect,
                                  TReal32 aBorderWidth,
                                  TReal32 aBorderHeight, 
                                  THuiRealPoint aOffset,
                                  const THuiImage* aImage) __SOFTFP
    {
    // If there is no image, draw a solid border
    if (!aImage || !aImage->HasTexture())
        {
        //
        // The border is drawn like this:
        //
        //      +-----------------+
        //      |                 |
        //      +---+---------+   |
        //      |   |         |   |
        //      |   |         |   |
        //      |   |         |   |
        //      |   |         |   |
        //      |   +---------+   |
        //      |                 |
        //      +-----------------+
        //
        // We do not use a path with a hole, because some of the edges might become too thin.
        //
        TReal32 w = aOuterRect.Width();
        TReal32 h = aOuterRect.Height();

        const VGfloat borderCoords[10 * 2] = 
            {
            aOuterRect.iTl.iX, aOuterRect.iTl.iY,
            w, 0.0f,
            0.0f, h,
            -w, 0.0f,
            0.0f, -h + aBorderWidth,
            aBorderWidth, 0.0f,
            0.0f, h - aBorderHeight - aBorderHeight,
            w - aBorderHeight - aBorderHeight, 0.0f,
            0.0f, -h + aBorderHeight + aBorderHeight,
            -w + aBorderWidth, 0.0f,
            };

        UpdateMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
        vgModifyPathCoords(iBorderPath, 0, 12, borderCoords);
        vgDrawPath(iBorderPath, VG_FILL_PATH);
        
        HUI_VG_INVARIANT();
        return;
        }
    
    THuiRealRect texCoords = GetSourceRectangleFromImage(*aImage);
    THuiRealPoint midTexCoord((texCoords.iTl.iX + texCoords.iBr.iX) * .5f,
                              (texCoords.iTl.iY + texCoords.iBr.iY) * .5f);

    THuiRealRect outerRect(aOuterRect);
    outerRect.iTl += aOffset;
    outerRect.iBr += aOffset;
    THuiRealRect innerRect(aOuterRect);
    innerRect.Shrink(aBorderWidth, aBorderHeight);

    // Top left segment
    DrawCroppedTexture(aImage->Texture(), 
                       THuiRealRect(texCoords.iTl, midTexCoord), 
                       THuiRealRect(outerRect.iTl, innerRect.iTl));

    // Top segment
    DrawCroppedTexture(aImage->Texture(), 
                       THuiRealRect(THuiRealPoint(midTexCoord.iX, texCoords.iTl.iY), midTexCoord),
                       THuiRealRect(THuiRealPoint(innerRect.iTl.iX, outerRect.iTl.iY), innerRect.TopRight()));

    // Top right segment
    DrawCroppedTexture(aImage->Texture(), 
                       THuiRealRect(THuiRealPoint(midTexCoord.iX, texCoords.iTl.iY),
                                    THuiRealPoint(texCoords.iBr.iX, midTexCoord.iY)),
                       THuiRealRect(THuiRealPoint(innerRect.iBr.iX, outerRect.iTl.iY),
                                    THuiRealPoint(outerRect.iBr.iX, innerRect.iTl.iY)));

    // Right segment
    DrawCroppedTexture(aImage->Texture(), 
                       THuiRealRect(midTexCoord, 
                                    THuiRealPoint(texCoords.iBr.iX, midTexCoord.iY)),
                       THuiRealRect(innerRect.TopRight(),
                                    THuiRealPoint(outerRect.iBr.iX, innerRect.iBr.iY)));

    // Bottom right segment
    DrawCroppedTexture(aImage->Texture(), 
                       THuiRealRect(midTexCoord, texCoords.iBr),
                       THuiRealRect(innerRect.iBr, outerRect.iBr));

    // Bottom segment
    DrawCroppedTexture(aImage->Texture(), 
                       THuiRealRect(midTexCoord, 
                                    THuiRealPoint(midTexCoord.iX, texCoords.iBr.iY)),
                       THuiRealRect(innerRect.BottomLeft(),
                                    THuiRealPoint(innerRect.iBr.iX, outerRect.iBr.iY)));

    // Bottom left segment
    DrawCroppedTexture(aImage->Texture(), 
                       THuiRealRect(THuiRealPoint(texCoords.iTl.iX, midTexCoord.iY),
                                    THuiRealPoint(midTexCoord.iX, texCoords.iBr.iY)),
                       THuiRealRect(THuiRealPoint(outerRect.iTl.iX, innerRect.iBr.iY),
                                    THuiRealPoint(innerRect.iTl.iX, outerRect.iBr.iY)));

    // Left segment
    DrawCroppedTexture(aImage->Texture(), 
                       THuiRealRect(THuiRealPoint(texCoords.iTl.iX, midTexCoord.iY), 
                                    midTexCoord),
                       THuiRealRect(THuiRealPoint(outerRect.iTl.iX, innerRect.iTl.iY),
                                    innerRect.BottomLeft()));
    HUI_VG_INVARIANT();
    }

void CHuiVg10Gc::DrawBorderFixedCorners(const TRect& aOuterRect, 
                                        TReal32 aLeftBorderWidth,
                                        TReal32 aRightBorderWidth, 
                                        TReal32 aTopBorderHeight,
                                        TReal32 aBottomBorderHeight, 
                                        const THuiImage* aImage) __SOFTFP
    {
    // If there is no image, draw a solid border
    if (!aImage || !aImage->HasTexture())
        {
        //
        // The border is drawn like this:
        //
        //      +-----------------+
        //      |                 |
        //      +---+---------+   |
        //      |   |         |   |
        //      |   |         |   |
        //      |   |         |   |
        //      |   |         |   |
        //      |   +---------+   |
        //      |                 |
        //      +-----------------+
        //
        // We do not use a path with a hole, because some of the edges might become too thin.
        //
        TReal32 w = aOuterRect.Width();
        TReal32 h = aOuterRect.Height();

        const VGfloat borderCoords[10 * 2] = 
            {
            aOuterRect.iTl.iX, aOuterRect.iTl.iY,
            w, 0.0f,
            0.0f, h,
            -w, 0.0f,
            0.0f, -h + aTopBorderHeight,
            aLeftBorderWidth, 0.0f,
            0.0f, h - aTopBorderHeight - aBottomBorderHeight,
            w - aLeftBorderWidth - aRightBorderWidth, 0.0f,
            0.0f, -h + aTopBorderHeight + aBottomBorderHeight,
            -w + aRightBorderWidth, 0.0f,
            };

        UpdateMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
        vgModifyPathCoords(iBorderPath, 0, 12, borderCoords);
        vgDrawPath(iBorderPath, VG_FILL_PATH);
        
        HUI_VG_INVARIANT();
        return;
        }
    
    THuiRealRect texCoords = GetSourceRectangleFromImage(*aImage);
    THuiRealRect innerTexCoords(texCoords);
    THuiRealSize texSize = aImage->Texture().Size();
    THuiRealRect outerRect(aOuterRect);
    THuiRealRect innerRect(aOuterRect);
    
    innerTexCoords.iTl.iX += aLeftBorderWidth    / texSize.iWidth;
    innerTexCoords.iTl.iY += aTopBorderHeight    / texSize.iHeight;
    innerTexCoords.iBr.iX -= aRightBorderWidth   / texSize.iWidth;
    innerTexCoords.iBr.iY -= aBottomBorderHeight / texSize.iHeight;

    innerRect.iTl.iX += aLeftBorderWidth;
    innerRect.iTl.iY += aTopBorderHeight;
    innerRect.iBr.iX -= aRightBorderWidth;
    innerRect.iBr.iY -= aBottomBorderHeight;

    // Top left segment
    if (aTopBorderHeight > 0.0f && aLeftBorderWidth > 0.0f)
        {
        DrawCroppedTexture(aImage->Texture(), 
                         THuiRealRect(texCoords.iTl, innerTexCoords.iTl), 
                         THuiRealRect(outerRect.iTl, innerRect.iTl));
        }

    // Top segment
    if (aTopBorderHeight > 0.0f)
        {
        DrawCroppedTexture(aImage->Texture(), 
                           THuiRealRect(THuiRealPoint(innerTexCoords.iTl.iX, texCoords.iTl.iY), 
                                        innerTexCoords.TopRight()),
                           THuiRealRect(THuiRealPoint(innerRect.iTl.iX, outerRect.iTl.iY), 
                                        innerRect.TopRight()));
        }

    // Top right segment
    if (aTopBorderHeight > 0.0f && aRightBorderWidth > 0.0f)
        {
        DrawCroppedTexture(aImage->Texture(), 
                           THuiRealRect(THuiRealPoint(innerTexCoords.iBr.iX, texCoords.iTl.iY),
                                        THuiRealPoint(texCoords.iBr.iX, innerTexCoords.iTl.iY)),
                           THuiRealRect(THuiRealPoint(innerRect.iBr.iX, outerRect.iTl.iY),
                                        THuiRealPoint(outerRect.iBr.iX, innerRect.iTl.iY)));
        }

    // Right segment
    if (aRightBorderWidth > 0.0f)
        {
        DrawCroppedTexture(aImage->Texture(), 
                           THuiRealRect(innerTexCoords.TopRight(), 
                                        THuiRealPoint(texCoords.iBr.iX, innerTexCoords.iBr.iY)),
                           THuiRealRect(innerRect.TopRight(),
                                        THuiRealPoint(outerRect.iBr.iX, innerRect.iBr.iY)));
        }

    // Bottom right segment
    if (aBottomBorderHeight > 0.0f && aRightBorderWidth > 0.0f)
        {
        DrawCroppedTexture(aImage->Texture(), 
                           THuiRealRect(innerTexCoords.iBr, texCoords.iBr),
                           THuiRealRect(innerRect.iBr, outerRect.iBr));
        }

    // Bottom segment
    if (aRightBorderWidth > 0.0f)
        {
        DrawCroppedTexture(aImage->Texture(), 
                           THuiRealRect(innerTexCoords.BottomLeft(),
                                        THuiRealPoint(innerTexCoords.iBr.iX, texCoords.iBr.iY)),
                           THuiRealRect(innerRect.BottomLeft(),
                                        THuiRealPoint(innerRect.iBr.iX, outerRect.iBr.iY)));
        }

    // Bottom left segment
    if (aBottomBorderHeight > 0.0f && aRightBorderWidth > 0.0f)
        {
        DrawCroppedTexture(aImage->Texture(), 
                           THuiRealRect(THuiRealPoint(texCoords.iTl.iX, innerTexCoords.iBr.iY),
                                        THuiRealPoint(innerTexCoords.iTl.iX, texCoords.iBr.iY)),
                           THuiRealRect(THuiRealPoint(outerRect.iTl.iX, innerRect.iBr.iY),
                                        THuiRealPoint(innerRect.iTl.iX, outerRect.iBr.iY)));
        }

    // Left segment
    if (aLeftBorderWidth > 0.0f)
        {
        DrawCroppedTexture(aImage->Texture(), 
                           THuiRealRect(THuiRealPoint(texCoords.iTl.iX, innerTexCoords.iTl.iY), 
                                        innerTexCoords.BottomLeft()),
                           THuiRealRect(THuiRealPoint(outerRect.iTl.iX, innerRect.iTl.iY),
                                        innerRect.BottomLeft()));
        }
    HUI_VG_INVARIANT();
    }

void CHuiVg10Gc::DrawPath(const CHuiCurvePath& aPath,
                            const TPoint& aOrigin,
                            TReal32 aStartPos,
                            TReal32 aEndPos,
                            MHuiMappingFunction* aAlphaFunction,
                            MHuiMappingFunction* aWidthFunction) __SOFTFP
    {
    // Refresh the vertices.
    CHuiCurvePath* nonConstCurvePath = const_cast<CHuiCurvePath*>(&aPath);
    nonConstCurvePath->Update(aStartPos, aEndPos, PenAlpha() / 255.f,
                              aAlphaFunction, aWidthFunction);

    aPath.Draw(aOrigin, this);
    HUI_VG_INVARIANT();
    }


void CHuiVg10Gc::DrawMesh(const CHuiMesh& /*aMesh*/, const THuiImage* /*aImage*/,
                            const THuiImage* /*aSecondaryImage*/,
                            TReal32 /*aSecondaryAlpha*/) __SOFTFP
    {
    HUI_DEBUGF(_L("CHuiVg10Gc::DrawMesh() - Method has not been implemented! Sorry."));     
    }

void CHuiVg10Gc::DrawArc(const TPoint& /*aOrigin*/, const TSize& /*aRadius*/,
                           TReal32 /*aEnd*/, TReal32 /*aStart*/, TInt /*aAnglePerSegment*/,
                           TReal32 /*aWidth*/, const THuiImage& /*aImage*/,
                           TReal32 (aAlphaFunc)(TReal32), TBool /*aAbsoluteAngleParm*/) __SOFTFP
    {
	 // not supported
	aAlphaFunc(1.0); // just to disable compiler warning
    return;
    }



void CHuiVg10Gc::DrawGradient(TGradientType aType, const TRect& aRect,
                              const TRgb& aStartColor, const TRgb& aEndColor,
                              TReal32 aStartOpacity, TReal32 aEndOpacity,
                              const THuiRealRect* aTexCoords) __SOFTFP
    {
    VGfloat gradientCoords[4];
    VGfloat x1 = (VGfloat)aRect.iTl.iX;
    VGfloat y1 = (VGfloat)aRect.iTl.iY;
    VGfloat x2 = (VGfloat)aRect.iBr.iX;
    VGfloat y2 = (VGfloat)aRect.iBr.iY;
    
    switch (aType)
        {
        case EGradientLinearUp:
            gradientCoords[0] = x1;  gradientCoords[1] = y2;
            gradientCoords[2] = x1;  gradientCoords[3] = y1;
            break;
        case EGradientLinearRight:
            gradientCoords[0] = x1;  gradientCoords[1] = y1;
            gradientCoords[2] = x2;  gradientCoords[3] = y1;
            break;
        case EGradientLinearDown:
            gradientCoords[0] = x1;  gradientCoords[1] = y1;
            gradientCoords[2] = x1;  gradientCoords[3] = y2;
            break;
        case EGradientLinearLeft:
            gradientCoords[0] = x2;  gradientCoords[1] = y1;
            gradientCoords[2] = x1;  gradientCoords[3] = y1;
            break;
        }

    VGfloat scale = 1.0f / 255.0f;
    const VGfloat gradientStops[] =
        {
        0.0f,  aStartColor.Red() * scale, aStartColor.Green() * scale, aStartColor.Blue() * scale, aStartOpacity,
        1.0f,  aEndColor.Red()   * scale, aEndColor.Green()   * scale, aEndColor.Blue()   * scale, aEndOpacity,
        };
    
    vgSetParameterfv(iGradientPaint, VG_PAINT_LINEAR_GRADIENT, 2 * 2, gradientCoords);
    vgSetParameterfv(iGradientPaint, VG_PAINT_COLOR_RAMP_STOPS, 2 * 5, gradientStops);
    vgSetPaint(iGradientPaint, VG_FILL_PATH);
    HUI_VG_INVARIANT();

    UpdateColor();
    UpdateMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
    
    // Draw the gradient as an image if we have a texture, otherwise draw a regular rectangle
    if (aTexCoords)
        {
        /*
        CHuiDisplay* display = CHuiStatic::Env().CurrentDisplay();

        if (!display)
            {
            THuiPanic::Panic(THuiPanic::EVg10Invariant);
            }
        CHuiVg10RenderSurface* surface = static_cast<CHuiVg10RenderSurface*>(&display->RenderSurface());
		*/
		
        CHuiVg10RenderSurface* surface = static_cast<CHuiVg10RenderSurface*>(CHuiStatic::CurrentRenderSurface());

        if (!surface)
            {
            THuiPanic::Panic(THuiPanic::EVg10Invariant);
            }
        
        const MHuiSegmentedTexture* tex = surface->BoundTexture();

        if (!tex)
            {
            DrawRect(aRect);
            }
        else
            {
            vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_MULTIPLY); // Will be restored by next call to UpdateColor()
            DrawTexture(*tex, *aTexCoords, aRect);
            }
        }
    else
        {
        DrawRect(aRect);
        }
    HUI_VG_INVARIANT();
    
    // Restore the original paint
    vgSetPaint(iPaint, VG_FILL_PATH | VG_STROKE_PATH);
    UpdateColor();
    }


void CHuiVg10Gc::SetDepthOffset(TInt /*aOffset*/)
    {
    // No depth offset on OpenVG
    }


TUint8* CHuiVg10Gc::CaptureLC(TSize& aSize) const
    {
    TRect displayArea = RawDisplayArea();

    TUint8* buffer = new (ELeave) TUint8[displayArea.Width() *
                                         displayArea.Height() * 4];
    CleanupStack::PushL(buffer);

    aSize = displayArea.Size();
    vgReadPixels(buffer, displayArea.Width() * 4, VG_lARGB_8888, 0, 0, 
                 displayArea.Width(), displayArea.Height());

    return buffer;
    }

#ifdef __NVG
void CHuiVg10Gc::DrawNVG(HBufC8* aNVGData, MNVGIcon* aIconCmds, const TSize& aImageSize, TBool aIgnoreAspectRatio)
    {
    HUI_VG_INVARIANT();
    
    if (!aNVGData)
        return;
    // Parse the icon header info from the extended data
    TPtr8 IconHeaderPtr((TUint8 *)aNVGData->Des().Ptr(), KIconHeaderLength, KIconHeaderLength);
    TAknIconHeader iconheader(IconHeaderPtr);

    // The rest of the data (after the iconheader) are the OVG drawing instructions
    TInt lengthAfterHeader = aNVGData->Length() - KIconHeaderLength;
    TPtr8 nvgDataVoidIC((TUint8 *)aNVGData->Des().Ptr() + KIconHeaderLength, lengthAfterHeader, lengthAfterHeader);
    
    // Set the rotation angle
    iNvgEngine->Rotate(iconheader.GetRotation(), aImageSize.iWidth >>1, aImageSize.iHeight >>1);
    
    if (aIgnoreAspectRatio == EFalse)
    {
        // Set preserve aspect ratio (if not ignored)
        TNvgAlignStatusType alignTypeValue = ENvgPreserveAspectRatio_XmidYmid;
        TNvgMeetOrSliceType meetOrSliceTypeValue = ENvgMeet;
        
        switch ( iconheader.GetScaleMode() )
            {
            case EAspectRatioPreserved:
                {
                // Use default
                break;
                }
            // Ensures NVG content fully covers the area
            // of the icon whilst preserving aspect ratio.
            case EAspectRatioPreservedSlice:
                {
                // alignTypeValue use default
                meetOrSliceTypeValue = ENvgSlice;
                break;
                }
            // EAspectRatioPreservedAndUnusedSpaceRemoved is mapped to the same
            // values as EAspectRatioNotPreserved because we already have a
            // frame buffer with the dimensions that preserves the aspect ratio.
            // This mapping ensures that NVG engine does not calculate aspect
            // ratio twice and potentially resulting in precision loss.
            case EAspectRatioPreservedAndUnusedSpaceRemoved:
            case EAspectRatioNotPreserved:
                {            
                alignTypeValue = ENvgPreserveAspectRatio_None;
                // meetOrSliceTypeValue use default
                break;
                }
            }
        iNvgEngine->SetPreserveAspectRatio(alignTypeValue, meetOrSliceTypeValue);
    }
    
    // Draw the NVG path onto the current surface using the NVGEngine
    if (aIconCmds)
        {
        aIconCmds->Draw(aImageSize, iNvgEngine);
        }
    else
        {
        // Fall back drawing directly from the nvg data
        HUI_DEBUG(_L("CHuiVg10Gc::DrawNVG() - Fallback to draw the old way (via DrawNvg)"));
        iNvgEngine->DrawNvg(nvgDataVoidIC, aImageSize, NULL, NULL);
        }
    
    // The NVG draw messes up the paint, scissoring & rects, so mark them as dirty
    TInt dirtyFlags = EHuiVg10GcStateFlagDirtyPaint |
                    EHuiVg10GcStateFlagDirtyScissor | 
                    EHuiVg10GcStateFlagDirtyScissorRects;
    ((CHuiVg10RenderPlugin&)CHuiStatic::Renderer()).AddRestoreStateFlags(dirtyFlags);
    // Restore the paint etc.
    RestoreFlaggedState();

    HUI_VG_INVARIANT();
    }
#endif

void CHuiVg10Gc::TransformDirtyRect(THuiRealRect& aRect)
    {
    THuiRealRect transformed = aRect;
    
    // Transform the rectangle using our stacks
    UpdateClientMatrix();
    iMatrixStack->Current().Multiply(transformed.iTl);
    iMatrixStack->Current().Multiply(transformed.iBr);
    
    // Normalize the rectangle
    if (transformed.iTl.iX > transformed.iBr.iX)
        {
        TReal32 tmp = transformed.iTl.iX;
        transformed.iTl.iX = transformed.iBr.iX;
        transformed.iBr.iX = tmp;
        }
    if (transformed.iTl.iY > transformed.iBr.iY)
        {
        TReal32 tmp = transformed.iTl.iY;
        transformed.iTl.iY = transformed.iBr.iY;
        transformed.iBr.iY = tmp;
        }    

    aRect = transformed;
    }

void CHuiVg10Gc::SetPaintPattern(CHuiTexture* aTexture, const TPoint& aTextureOrigin)
    {
    if (aTexture)
        {
        // TODO: This does not work if texture has NVG data only
        iPaintPattern = GetVGImageFromTexture( *aTexture );
        }
    else
        {
        iPaintPattern = VG_INVALID_HANDLE;
        }

    if (iPaintPattern)
        {
        vgSetParameteri(iPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_PATTERN);
        vgSetParameteri(iPaint, VG_PAINT_PATTERN_TILING_MODE, VG_TILE_REPEAT);        
        iPaintPatternOrigin = aTextureOrigin;
        }
    else
        {
        vgSetParameteri(iPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
        vgSetParameteri(iPaint, VG_PAINT_PATTERN_TILING_MODE, VG_TILE_FILL);        
        iPaintPatternOrigin = TPoint(0,0);
        }
    
    vgPaintPattern(iPaint, iPaintPattern);
    }

void CHuiVg10Gc::UsePaintPattern()
    {
    if (iPaintPattern)
        {
        // Transform the paint pattern to fill the destination rectangle as required
        vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER);
        vgLoadIdentity();
        vgTranslate(iPaintPatternOrigin.iX, iPaintPatternOrigin.iY);
        vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
        }
    }

void CHuiVg10Gc::DiscardPaintPattern()
    {
    if (iPaintPattern)
        {
        // Restore
        vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER);
        vgLoadIdentity();
        vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
        }
    }

void CHuiVg10Gc::GcExtension(const TUid& aExtensionUid, TAny** aExtensionParams)
    {
    if ( aExtensionUid == KHuiGcCopyScreenToBitmap && aExtensionParams && *aExtensionParams)
        {
        THuiGcCopyScreenToBitmapParams* params = static_cast<THuiGcCopyScreenToBitmapParams*>(*aExtensionParams);
        params->iErrorCode = DoCopyScreenToBitmap(params->iBitmap);
        }
    else
        {
        CHuiGc::GcExtension(aExtensionUid, aExtensionParams);
        }
    }

TInt CHuiVg10Gc::DoCopyScreenToBitmap(CFbsBitmap* aBitmap)
    {
    if (!aBitmap || 
        !aBitmap->Handle() || 
        aBitmap->IsCompressedInRAM() || 
        aBitmap->ExtendedBitmapType() != KNullUid )
        {
        return KErrNotSupported;
        }

    VGImageFormat dataFormat = VG_sARGB_8888_PRE;
    TBool displayModeSupported = ETrue;    
    switch (aBitmap->DisplayMode())
        {
    case EColor16MAP:
        dataFormat = VG_sARGB_8888_PRE;
        break;
    case EColor64K:
        dataFormat = VG_sRGB_565;
        break;
    case EColor16MU:
        dataFormat = VG_sXRGB_8888;
        break;
    case EColor16MA:
        dataFormat = VG_sARGB_8888;
        break;

    default:
        displayModeSupported = EFalse;
        break;
        }
    
    if (!displayModeSupported)
        {
        return KErrNotSupported;
        }
        
    TRect copyRect(aBitmap->SizeInPixels());
    if (copyRect.IsEmpty())
        {
        return KErrArgument;
        }
    
    TInt dataStride = CFbsBitmap::ScanLineLength(copyRect.Width(), 
        aBitmap->DisplayMode());

    aBitmap->BeginDataAccess();
    TUint8* data = (TUint8*)aBitmap->DataAddress();
    
    // image is upside down..
    data += (copyRect.Height() - 1)*dataStride;
    dataStride = -dataStride;
    
    vgReadPixels(
        data,
        dataStride,
        dataFormat,
        0,                // sx
        0,                // sy
        copyRect.Width(), // width
        copyRect.Height() // height
        );
    
    aBitmap->EndDataAccess(EFalse);
    return KErrNone;
    }

// End of file

