svgtopt/nvgdecoder/src/nvg.cpp
changeset 0 d46562c3d99d
child 1 bfff372fb1f4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/svgtopt/nvgdecoder/src/nvg.cpp	Thu Jan 07 16:19:02 2010 +0200
@@ -0,0 +1,1717 @@
+/*
+* Copyright (c) 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:  NVG Decoder source file
+*
+*/
+
+ 
+#include <s32mem.h>
+#include <libc/math.h> 
+#include <e32math.h>
+
+#include "nvg.h"
+#include "nvgfittoviewbox.h"
+#include "NVGUtil.h"
+
+#include "NVGCSIcon.h"
+#include "NVGTLVIcon.h"
+#include "FloatFixPt.h"
+
+#include "NVGIconData.h"
+
+/*
+ * may be we should use dynamic_cast?
+ */
+#define CSICON(icon)      ((CNVGCSIcon *)icon) 
+#define TLVICON(icon)     ((CNVGTLVIcon *)icon) 
+
+enum TNVGFormats
+    {
+    ENVGCS,
+    ENVGTLV
+    };
+
+/*
+ *  NVG-CS version
+ */
+//const TInt KVersion1   = 1;
+const TInt KVersion2   = 2;
+
+/*
+ * constants for nvg file header offsets
+ */ 
+const TUint8 KNVG_SIGNATURE[]       = "nvg";
+const TInt KNVG_SIGNATURE_LENGTH    = sizeof(KNVG_SIGNATURE) - sizeof('\0');
+const TInt KNVG_COMMANDSECTION_OFS  = 2;
+const TInt KNVG_VERSION_OFS         = 3;
+const TInt KNVG_RGBA_OFS            = 4;
+const TInt KNVG_HEADERSIZE_OFS      = 4;
+const TInt KNVG_PATHDATATYPE_OFS    = 26;
+const TInt KNVG_SCALE_OFS           = 28;
+const TInt KNVG_BIAS_OFS            = 32;
+const TInt KNVG_VIEWBOX_X_OFS       = 36;
+const TInt KNVG_VIEWBOX_Y_OFS       = 40;
+const TInt KNVG_VIEWBOX_WIDTH_OFS   = 44;
+const TInt KNVG_VIEWBOX_HEIGHT_OFS  = 48;
+
+const TInt KNVG_PAINTSECTION_LINEARGRAD_TRANSFORM_OFFSET = 20;
+const TInt KNVG_PAINTSECTION_RADIALGRAD_TRANSFORM_OFFSET = 24;
+
+/*
+ * nvg-cs commands
+ */ 
+const TInt KCMD_SET_FILL_PAINT           = 4  << 24;
+const TInt KCMD_SET_COLOR_RAMP           = 6  << 24;
+const TInt KCMD_DRAW_PATH                = 7  << 24;
+const TInt KCMD_SET_TRANSFORMATION       = 8  << 24;
+const TInt KCMD_SET_STROKE_PAINT         = 5  << 24;
+const TInt KCMD_SET_STROKE_WIDTH         = 9  << 24;
+const TInt KCMD_SET_STROKE_LINE_JOIN_CAP = 10 << 24;
+const TInt KCMD_SET_STROKE_MITER_LIMIT   = 11 << 24;
+
+/*
+ * stroke cap style
+ */
+const TInt KCAP_BUTT        = 1;
+const TInt KCAP_SQUARE      = 2;
+const TInt KCAP_ROUND       = 3;
+
+/*
+ * stroke join style
+ */
+const TInt KLINE_JOIN_BEVEL = 1;
+const TInt KLINE_JOIN_MITER = 2;
+const TInt KLINE_JOIN_ROUND = 3;
+
+/*
+ * fill paint type
+ */
+const TInt KPAINT_FLAT      = 1;
+const TInt KPAINT_LGRAD     = 2;
+const TInt KPAINT_RGRAD     = 3;
+
+/*
+ * stroke paint type
+ */
+const TInt KSTROKE_LGRAD        = 2;
+const TInt KSTROKE_RGRAD        = 3;
+const TInt KSTROKE_COLOR_RAMP   = 4;
+
+/*
+ * nvg offset
+ */
+const TInt KOffsetReserved1       = 6;
+
+/*
+ * transform encoding values
+ */
+const TInt KTRANSFORM_COMPLETE    = 0;
+const TInt KTRANSFORM_SCALING     = 2;
+const TInt KTRANSFORM_SHEARING    = 4;
+const TInt KTRANSFORM_ROTATION    = 8;
+const TInt KTRANSFORM_TRANSLATION = 16;
+
+#ifdef OPENVG_OBJECT_CACHING
+const VGfloat KIdentityMatrix[] = 
+    {
+    1.0f, 0.0f, 0.0f,
+    0.0f, 1.0f, 0.0f,
+    0.0f, 0.0f ,1.0f
+    };
+#endif
+
+/*
+ * function to delete array, for basic types
+ */
+GLDEF_C void CleanupArray( TAny * aObj )
+    {
+    delete [] aObj;
+    }
+
+/*
+ * function to delete array of TFloatFixArray
+ */
+GLDEF_C void CleanupTFloatFixArray( TAny * aObj )
+    {
+    TFloatFixPt * ff = (TFloatFixPt *)aObj;
+    delete [] ff;
+    }
+
+/**
+ * @class   TNVGEngineInternal
+ * This class is added to maintain BC.
+ * If you want to add new member variable you can add in this class, without breaking BC.
+ * It is better to add members which are depend on macro's in this class.
+ */
+class TNVGEngineInternal
+    {
+public:
+    TNVGEngineInternal()
+        {
+#ifdef    OPENVG_OBJECT_CACHING
+        iCreatingNVGIcon = 0;
+        iCurrentNVGIcon  = 0;
+#endif
+        }
+    
+#ifdef    OPENVG_OBJECT_CACHING
+    TInt        iCreatingNVGIcon;
+    MNVGIcon *  iCurrentNVGIcon;
+#endif
+    };
+
+CNvgEngine::CNvgEngine()
+    : iCurrentBufferSize(1, 1),
+      iPath(VG_INVALID_HANDLE),
+      iPaintFill(VG_INVALID_HANDLE),
+      iPaintStroke( VG_INVALID_HANDLE),
+      iUserStrokePaintColor(0xFFFFFFFF),
+      iRotateApplied(EFalse),
+      iLastPathDataType(0),
+      iPreserveAspectSetting(ENvgPreserveAspectRatio_XmidYmid),
+      iSmilFitSetting(ENvgMeet),
+      iVGImageBinder(0)
+    {
+    }
+
+EXPORT_C CNvgEngine* CNvgEngine::NewL()
+    {
+    CNvgEngine* self    = new (ELeave) CNvgEngine;
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+void CNvgEngine::ConstructL()
+    {
+    vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_BETTER);
+    vgSeti(VG_FILL_RULE, VG_NON_ZERO);
+    
+    iInternal = new (ELeave) TNVGEngineInternal;
+    iPaintFill = vgCreatePaint();
+    }
+
+EXPORT_C CNvgEngine::~CNvgEngine()
+    {
+    if (iPath != VG_INVALID_HANDLE)
+        {
+        vgDestroyPath(iPath);
+        }
+    
+    if (iPaintFill != VG_INVALID_HANDLE)
+        {
+        vgSetPaint(VG_INVALID_HANDLE, VG_FILL_PATH);
+        vgDestroyPaint(iPaintFill);
+        }
+		
+    if (iPaintStroke != VG_INVALID_HANDLE)
+        {
+        vgSetPaint(VG_INVALID_HANDLE, VG_STROKE_PATH);
+        vgDestroyPaint(iPaintStroke);
+        }
+
+    
+#ifdef    OPENVG_OBJECT_CACHING
+    if (iInternal)
+        {
+        delete iInternal->iCurrentNVGIcon;
+        }
+#endif
+    
+    delete iInternal;
+    }
+
+/**
+ * @brief  Set the angle for rotation of the NVG graphic
+ * @version
+ * @param    aAngle counter-clockwise rotation by a given angle (expressed in degrees)
+ *              aX, aY  point around which the rotation must take place
+ * @return  None
+ */
+EXPORT_C void CNvgEngine::Rotate(TReal32 aAngle, TReal32 aCentreX, TReal32 aCentreY) __SOFTFP
+    {
+    if(aAngle)
+        {
+        iRotateApplied  = ETrue;
+        iCentreX        = aCentreX;
+        iCentreY        = aCentreY;
+        iRotateAngle    = aAngle;
+        }
+    else
+        {
+        iRotateApplied  = EFalse;
+        iCentreX        = 0;
+        iCentreY        = 0;
+        iRotateAngle    = 0;
+        }
+    }
+
+/**
+ * @brief  Gets the viewbox width and height from the NVG bytedata
+ * @version
+ * @param   aBuf NVG byte data of the file
+ * @return  content dimension
+ */
+EXPORT_C TSize CNvgEngine::ContentDimensions(const TDesC8& aBuf)
+    {
+    if (aBuf.Length() < KNVG_VIEWBOX_HEIGHT_OFS + sizeof (TReal32))
+        {
+        return TSize(0, 0);
+        }
+    
+    const TUint8* lBuf = aBuf.Ptr();
+    TReal32 lViewboxWidth = * (TReal32*)(lBuf + KNVG_VIEWBOX_WIDTH_OFS);
+    TReal32 lViewboxHeight = * (TReal32*)(lBuf + KNVG_VIEWBOX_HEIGHT_OFS);
+    
+    if (lViewboxWidth > 0 && lViewboxHeight > 0)
+        {
+        return TSize(lViewboxWidth, lViewboxHeight);
+        }
+    else
+        {
+        return TSize(0, 0);
+        }
+    }
+
+TInt CNvgEngine::InitializeGC()
+    {
+    if (iPaintFill == VG_INVALID_HANDLE)
+        {
+        iPaintFill = vgCreatePaint();
+        if (iPaintFill == VG_INVALID_HANDLE)
+            {
+            return OpenVGErrorToSymbianError(vgGetError());
+            }
+        }
+    
+    vgSetPaint(iPaintFill, VG_FILL_PATH);
+    if (iPaintStroke == VG_INVALID_HANDLE)
+        {
+        iPaintStroke = vgCreatePaint();
+        if (iPaintStroke == VG_INVALID_HANDLE)
+            {
+            return OpenVGErrorToSymbianError(vgGetError());
+            }
+        }
+    
+    vgSetPaint( iPaintStroke, VG_STROKE_PATH);
+    
+    return KErrNone;
+    }
+
+EXPORT_C void CNvgEngine::ResetNvgState()
+    {
+    if (iPath != VG_INVALID_HANDLE)
+        {
+        vgDestroyPath(iPath);
+        iPath = VG_INVALID_HANDLE;
+        }
+    
+    if (iPaintFill != VG_INVALID_HANDLE)
+        {
+        vgSetPaint(VG_INVALID_HANDLE, VG_FILL_PATH);
+        vgDestroyPaint(iPaintFill);
+        iPaintFill = VG_INVALID_HANDLE;
+        }
+		
+    if (iPaintStroke != VG_INVALID_HANDLE)
+        {
+        vgSetPaint(VG_INVALID_HANDLE, VG_STROKE_PATH);
+        vgDestroyPaint(iPaintStroke);
+        iPaintStroke = VG_INVALID_HANDLE;
+        }
+    }
+
+EXPORT_C TInt CNvgEngine::DrawNvg(const TDesC8& aBuf, const TSize& aSize, CFbsBitmap* aDstBitmap, CFbsBitmap* aMask)
+    {
+    TInt error = KErrNone;
+    
+    /*
+     * Get Matrix modes and all caller matrices (must be restored afterwards)
+     */ 
+    UpdateClientMatrices();
+    
+    TRAP(error, DoDrawNVGL(aBuf, aSize, aDstBitmap, aMask));
+    
+    /*
+     * restore everything as we may have changed matrix mode
+     */             
+    RestoreClientMatrices();
+	vgSeti(VG_SCISSORING, VG_FALSE);
+
+	if (error)
+	    {
+	    NVG_DEBUGP2("Error in NVG rendering %d", error);
+	    }
+    return error;
+    }
+
+EXPORT_C MNVGIcon * CNvgEngine::CreateNVGIcon(const TDesC8& aBuf, const TSize& aSize)
+    {    
+    NVG_DEBUGP1("Creating NVGCSIcon");
+    
+    MNVGIcon * nvgIcon = 0;
+
+    /*
+     * this is bit unreadable,
+     * need to find a better design to separate the object caching solution from normal rendering,
+     * but anyway I guess its better than those ifdef's, in that code scanner won't give any warnings
+     */
+    COND_COM_OC_NOC(
+    {
+    if (iInternal->iCurrentNVGIcon)
+        {
+        delete iInternal->iCurrentNVGIcon;
+        }
+    
+    iInternal->iCurrentNVGIcon     = 0;
+    iInternal->iCreatingNVGIcon    = 1;
+    
+    if (DrawNvg(aBuf, aSize, 0, 0) != KErrNone)
+        {
+        delete iInternal->iCurrentNVGIcon;
+        iInternal->iCurrentNVGIcon = 0;
+        }
+    
+    iInternal->iCreatingNVGIcon    = 0;
+    nvgIcon = iInternal->iCurrentNVGIcon;
+    iInternal->iCurrentNVGIcon = 0;
+    },
+    {
+    (void)aBuf;
+    (void)aSize;
+    });
+
+    return nvgIcon;
+    }
+
+void CNvgEngine::DoDrawNVGL(const TDesC8& aBuffer, const TSize& aSize, CFbsBitmap* aDstBitmap, CFbsBitmap* aMask)
+    {
+    TInt drawStatus = KErrNone;
+
+    if (iCurrentBufferSize != aSize)
+        { 
+        iCurrentBufferSize = aSize;
+        }
+    
+    iDstBimtap = aDstBitmap;
+    
+    TDereferencer nvgIconData(aBuffer);
+
+    TUint8 * signature = nvgIconData.DerefInt8ArrayL(KNVG_SIGNATURE_LENGTH);
+
+    // checking the 'nvg' signature
+    if (Mem::Compare(signature, KNVG_SIGNATURE_LENGTH, KNVG_SIGNATURE, KNVG_SIGNATURE_LENGTH) != 0)
+        {
+        NVG_DEBUGP1("Not an NVG icon");
+        User::Leave(KErrNotSupported);
+        }
+
+    // last two bits are for identifying the nvg type. currently nvg-cs or nvg-tlv
+    TUint16   nvgType = nvgIconData.DerefInt16L(KOffsetReserved1) & 0x03;
+    
+    switch (nvgType)
+        {
+        case ENVGCS:
+            {
+            drawStatus = DrawCommandSectionL(&nvgIconData, aSize, aDstBitmap, aMask);
+            break;
+            }
+        case ENVGTLV:
+            {
+            drawStatus = DrawTLVL(aBuffer, aSize, aDstBitmap, aMask);
+            break;
+            }
+        default:
+            drawStatus = KErrNotSupported;
+            break;
+        }
+    
+    User::LeaveIfError(drawStatus);
+    }
+
+TInt CNvgEngine::DrawTLVL(const TDesC8& aBuf, const TSize& aTargetSize, CFbsBitmap* /*aDstBitmap*/, CFbsBitmap * /*aMask*/)
+    {
+    TInt ret = KErrNone;
+    
+    // Try to set user's matrix to path matrix
+    VGfloat origMatrix[9];
+    vgGetMatrix(origMatrix);
+    
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); 
+    vgLoadMatrix(origMatrix);
+    
+#ifndef __MIRROR_
+    vgScale(1.0f, -1.0f);
+    vgTranslate(0, (VGfloat)(-iCurrentBufferSize.iHeight));
+#endif
+
+    /*
+     * this is bit unreadable,
+     * need to find a better design to separate the object caching solution from normal rendering,
+     * but anyway I guess its better than those ifdef's, in that code scanner won't give any warnings
+     */
+    COND_COM_OC_NOC(
+    {
+    if (iInternal->iCreatingNVGIcon)
+        {
+        iInternal->iCurrentNVGIcon = CNVGTLVIcon::NewL();
+        TLVICON(iInternal->iCurrentNVGIcon)->SetVGImageBinder(iVGImageBinder);
+        TLVICON(iInternal->iCurrentNVGIcon)->CreateL(aBuf, aTargetSize);
+        }
+    else
+        {
+        CNVGTLVIcon * tlvIcon = CNVGTLVIcon::NewL();
+        CleanupStack::PushL(tlvIcon);
+        tlvIcon->SetVGImageBinder(iVGImageBinder);
+        tlvIcon->DirectDrawL(aBuf, aTargetSize);
+        CleanupStack::PopAndDestroy(tlvIcon);        
+        }
+
+    },
+    {
+    CNVGTLVIcon * tlvIcon = CNVGTLVIcon::NewL();
+    CleanupStack::PushL(tlvIcon);
+    TLVICON(tlvIcon)->SetVGImageBinder(iVGImageBinder);
+    TLVICON(tlvIcon)->DirectDrawL(aBuf, aTargetSize);
+    CleanupStack::PopAndDestroy(tlvIcon);                    
+    });
+    
+    vgSeti(VG_SCISSORING, VG_FALSE);
+    
+    return ret;
+    }
+
+TInt CNvgEngine::CreatePathHandle(TInt16 aPathDataType, TReal32 aScale, TReal32 aBias)
+    {
+    (void) aScale;
+    (void) aBias;
+    
+    TInt error = KErrNone;
+    
+    if (iLastPathDataType != aPathDataType)
+        {
+        if (iPath != VG_INVALID_HANDLE)
+            {
+            vgDestroyPath(iPath);
+            iPath = VG_INVALID_HANDLE;
+            }
+        }
+    
+    if (iPath == VG_INVALID_HANDLE)
+        {
+        switch (aPathDataType)
+            {
+            case EEightBitEncoding:
+                {
+                iPath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
+                VG_PATH_DATATYPE_S_16, 1.0f/2.0f, 0.0f, 0, 0,
+                VG_PATH_CAPABILITY_APPEND_TO);            
+                }
+                break;
+                       
+            case ESixteenBitEncoding:
+                {
+                iPath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
+                VG_PATH_DATATYPE_S_16, 1.0f/16.0f, 0.0f, 0, 0,
+                VG_PATH_CAPABILITY_APPEND_TO);            
+                }
+                break;
+                       
+            case EThirtyTwoBitEncoding:
+                {
+                iPath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
+                VG_PATH_DATATYPE_S_32, 1.0f/65536.0f, 0.0f, 0, 0,
+                VG_PATH_CAPABILITY_APPEND_TO);            
+                }
+                break;
+                       
+            default:
+                {   
+                return KErrCorrupt;
+                }
+            }
+        }
+    
+    if( iPath == VG_INVALID_HANDLE )
+        {
+        // get the symbian error code
+        error = OpenVGErrorToSymbianError(vgGetError());
+        
+        if (error == KErrNoMemory)
+            {
+            NVG_DEBUGP1("NVG Error OOM");
+            ResetNvgState();
+            }
+        return error;
+        }
+    
+    iLastPathDataType   = aPathDataType;
+
+    return error;
+    }
+
+TInt CNvgEngine::DrawCommandSectionL(TDereferencer * aIconData, const TSize& aTargetSize, CFbsBitmap * /*aDstBitmap*/, CFbsBitmap * /*aMask*/)
+    {
+    TInt16 lHeaderSize  = aIconData->DerefInt16L(KNVG_HEADERSIZE_OFS);
+    TInt8 NVGVersion    = aIconData->DerefInt8L(KNVG_VERSION_OFS);
+    
+    User::LeaveIfError(InitializeGC());
+
+    TInt16 lPathDataType = aIconData->DerefInt16L(KNVG_PATHDATATYPE_OFS);
+    TReal32 lScale       = aIconData->DerefReal32L(KNVG_SCALE_OFS);
+    TReal32 lBias        = aIconData->DerefReal32L(KNVG_BIAS_OFS);
+
+    User::LeaveIfError(CreatePathHandle(lPathDataType, lScale, lBias));
+    
+    vgSetPaint(iPaintFill, VG_FILL_PATH);
+    
+    COND_COM_OC_OOC(
+    if (iInternal->iCreatingNVGIcon)
+        {
+        iInternal->iCurrentNVGIcon = CNVGCSIcon::NewL(aIconData->GetPtr());
+        });
+    
+    VGfloat lCurrentPathMatrix[9];
+    vgGetMatrix(lCurrentPathMatrix);
+    
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);  
+    
+    /*
+     * We use the caller's base batrix regardless of which mode the caller was.
+     * The caller may have set the matrix in VG_MATRIX_IMAGE_USER_TO_SURFACE mode
+     * as it thinks it is drawing images (textures).
+     * But even though the texture gets stroked instead, we must use the caller's
+     * transformation matrix.
+     * Everything gets restored to the original values before we return.
+     */
+    vgLoadMatrix(lCurrentPathMatrix);
+    
+    ApplyScissoring(lCurrentPathMatrix, aTargetSize);
+
+    /*
+     * set the rotation angle if available
+     */
+    if (iRotateApplied)
+        {           
+        ApplyRotation();
+        }
+    
+#ifdef __MIRROR_    
+    vgScale(1.0f, -1.0f);
+    vgTranslate(0, (VGfloat)(-iCurrentBufferSize.iHeight) );
+#endif
+        
+    TReal32 lViewboxX   = aIconData->DerefReal32L(KNVG_VIEWBOX_X_OFS);
+    TReal32 lViewboxY   = aIconData->DerefReal32L(KNVG_VIEWBOX_Y_OFS);
+    TReal32 lViewboxW   = aIconData->DerefReal32L(KNVG_VIEWBOX_WIDTH_OFS);
+    TReal32 lViewboxH   = aIconData->DerefReal32L(KNVG_VIEWBOX_HEIGHT_OFS);
+     
+    ApplyViewboxToViewPortTransformationL(aTargetSize, lViewboxX, lViewboxY, lViewboxW, lViewboxH);
+    
+    TPtr8 ptr = aIconData->GetPtr();
+    
+    TInt offsetSectionLength = aIconData->GetLength() - lHeaderSize;
+    TUint8 * offsetPtr = aIconData->DerefInt8ArrayL(offsetSectionLength, lHeaderSize);
+    
+    TDereferencer offsetSection(offsetPtr, offsetSectionLength);
+
+    TUint16 lOffsetVectorCount  = offsetSection.DerefInt16L();
+
+    offsetPtr = aIconData->DerefInt8ArrayL(offsetSectionLength - sizeof(TUint16), lHeaderSize + sizeof(TUint16));
+    TDereferencer offsetVector(offsetPtr, offsetSectionLength - sizeof(TUint16));
+
+    idoFill     = VG_FALSE;
+    idoStroke   = VG_FALSE;
+    
+    TPtr8 offsetTPtr = offsetVector.GetPtr();
+    
+    TInt commandSectionOffset = lOffsetVectorCount * sizeof(TUint16);
+    TDereferencer commandSection((unsigned char*)(offsetTPtr.Ptr() + commandSectionOffset), 
+            aIconData->GetLength() - commandSectionOffset - lHeaderSize - sizeof(TUint16));
+
+    // from version 2 onwards command section will start on word boundary
+    if (NVGVersion >= KVersion2 && ((lOffsetVectorCount  & 0x01) == 0))
+        {
+        commandSection.SkipL(2);
+        }
+    
+    TUint16 lCmdCount = commandSection.DerefInt16L();
+    
+    commandSection.SkipL(KNVG_COMMANDSECTION_OFS);
+
+    /*
+     * from version 2 onwards there will be a padding added
+     * after the command count to make it word aligned
+     */
+    if (NVGVersion >= KVersion2)
+        {
+        commandSection.SkipL(2);
+        }
+
+    ExecuteNVGCSCommandLoopL(lCmdCount, aIconData, &offsetVector, &commandSection, NVGVersion);
+    
+    return KErrNone;
+    }
+
+void CNvgEngine::ApplyRotation()
+    {
+    vgTranslate(iCentreX, iCentreY);  
+    vgRotate(iRotateAngle);
+    vgTranslate(-iCentreX, -iCentreY);
+    }
+
+void CNvgEngine::ApplyScissoring(VGfloat aMatrix[], const TSize& aTargetSize)
+    {
+    /*
+     * calculate the rectangle with respect to the transformation applied
+     * and set the scissoring rect
+     */ 
+    TPoint leftBottom  = GetTranslatedPoint(aMatrix, TPoint(0, 0));
+    TPoint leftTop     = GetTranslatedPoint(aMatrix, TPoint(0, aTargetSize.iHeight));
+    TPoint rightBottom = GetTranslatedPoint(aMatrix, TPoint(aTargetSize.iWidth, 0));
+    TPoint rightTop    = GetTranslatedPoint(aMatrix, TPoint(aTargetSize.iWidth,aTargetSize.iHeight));
+
+    VGfloat minX = leftBottom.iX;
+    VGfloat minY = leftBottom.iY;
+    VGfloat maxX = leftBottom.iX;
+    VGfloat maxY = leftBottom.iY;
+
+    minX = MinVal4(leftBottom.iX, leftTop.iX, rightBottom.iX, rightTop.iX);
+    minY = MinVal4(leftBottom.iY, leftTop.iY, rightBottom.iY, rightTop.iY);
+
+    maxX = MaxVal4(leftBottom.iX, leftTop.iX, rightBottom.iX, rightTop.iX);
+    maxY = MaxVal4(leftBottom.iY, leftTop.iY, rightBottom.iY, rightTop.iY);
+
+    VGfloat newW = maxX - minX;
+    VGfloat newH = maxY - minY;
+
+    VGint clipRect[] = {minX, minY, newW, newH};
+
+    vgSeti(VG_SCISSORING, VG_TRUE);
+    vgSetiv(VG_SCISSOR_RECTS, 4,(const TInt32*) clipRect);
+    }
+
+void CNvgEngine::ApplyViewboxToViewPortTransformationL(const TSize& aTargetSize, TReal32 aViewboxX, TReal32 aViewboxY, TReal32 aViewboxW, TReal32 aViewboxH)
+    {
+    CNvgFitToViewBoxImpl * viewboxTrnsfr =  CNvgFitToViewBoxImpl::NewL();
+    CleanupStack::PushL(viewboxTrnsfr);
+    /*
+     * this is bit unreadable,
+     * need to find a better design to separate the object caching solution from normal rendering,
+     * but anyway I guess its better than those ifdef's, in that code scanner won't give any warnings
+     */
+    COND_COM_OC_NOC(
+    {
+    if (iInternal->iCreatingNVGIcon)
+        {
+        CSICON(iInternal->iCurrentNVGIcon)->SetViewBox(aViewboxX, aViewboxY, aViewboxW, aViewboxH);
+        CSICON(iInternal->iCurrentNVGIcon)->SetPreserveAspectRatio(iPreserveAspectSetting, iSmilFitSetting);
+        CSICON(iInternal->iCurrentNVGIcon)->Rotate(iRotateAngle, iCentreX, iCentreY);
+        }
+    else
+        {
+        viewboxTrnsfr->SetAlign(iPreserveAspectSetting);
+        viewboxTrnsfr->SetScaling(iSmilFitSetting);
+        
+        if (aViewboxW > 0 && aViewboxH > 0)
+            {
+            viewboxTrnsfr->SetViewBox(aViewboxX, aViewboxY, aViewboxW, aViewboxH);
+            }
+        
+        TInt lWidth = aTargetSize.iWidth;
+        TInt lHeight = aTargetSize.iHeight;
+        
+        viewboxTrnsfr->SetWindowViewportTrans(TRect(0, 0, lWidth, lHeight), TSize(0, 0));
+        
+        }
+    },
+    {
+    viewboxTrnsfr->SetAlign(iPreserveAspectSetting);
+    viewboxTrnsfr->SetScaling(iSmilFitSetting);
+    
+    if (aViewboxW > 0 && aViewboxH > 0)
+        {
+        viewboxTrnsfr->SetViewBox(aViewboxX, aViewboxY, aViewboxW, aViewboxH);
+        }
+    
+    TInt lWidth = aTargetSize.iWidth;
+    TInt lHeight = aTargetSize.iHeight;
+    
+    viewboxTrnsfr->SetWindowViewportTrans(TRect(0, 0, lWidth, lHeight), TSize(0, 0));
+    });
+    
+    CleanupStack::PopAndDestroy(viewboxTrnsfr);
+    }
+
+TDereferencer GetCommandSectionL(TUint16 aOffset, TDereferencer * aIconData, TInt aNVGVersion)
+    {
+    // the max length that the command section can have
+    TInt commandSectionLength = aIconData->GetLength() - aOffset;
+
+    if (commandSectionLength <= 0)
+        {
+        User::Leave(KErrCorrupt);
+        }
+
+    TDereferencer section(aIconData->DerefInt8ArrayL(commandSectionLength, aOffset), commandSectionLength);
+
+    /*
+     * all the section are expected to be word aligned
+     * all of the nvg-cs icon will be version 2 or above
+     * the else won't be there as nvg version will always be greater than 2
+     */
+    if (aNVGVersion >= KVersion2)
+        {
+        if (!IsAligned4(aOffset))
+            {
+            User::Leave(KErrCorrupt);
+            }
+        }
+    else
+        {
+        /*
+         * no need to do anything here as once the nvgdecoder release
+         * its version will be always greater than 2
+         * infact the check for version will be removed
+         */ 
+        }
+    
+    return section;
+    }
+
+void CNvgEngine::ExecuteNVGCSCommandLoopL(TUint16 aCommandCount, TDereferencer * aIconData, TDereferencer * aOffsetVector,
+                                          TDereferencer * aCommandSection, TInt aNVGVersion)
+    {
+    TUint32 transVal;
+
+    VGfloat lCurrentPathMatrix[9];
+    
+    vgGetMatrix(lCurrentPathMatrix);
+    
+    TInt32 lOffsetIx = 0;
+    for (TInt i=0; i < aCommandCount; i++)
+        {
+        TUint32 currentCommand = aCommandSection->DerefInt32L();
+        lOffsetIx = currentCommand & 0x0000ffff;
+                
+        switch (currentCommand & 0xff000000)
+            {
+            case KCMD_SET_FILL_PAINT:
+                {
+                iFillAlpha        = (currentCommand & 0x00ff0000) >> 16;
+                TUint16 offset    = aOffsetVector->DerefInt16L(lOffsetIx * sizeof(TUint16));
+                
+                TDereferencer section = GetCommandSectionL(offset, aIconData, aNVGVersion);
+                                
+                SetFillPaintL(&section);
+                
+                break;
+                }
+                
+            case KCMD_SET_COLOR_RAMP:
+                {
+                TUint16 offset = aOffsetVector->DerefInt16L(lOffsetIx * sizeof(TUint16));
+
+                TDereferencer section = GetCommandSectionL(offset, aIconData, aNVGVersion);
+
+                SetColorRampL(&section);
+                
+                break;
+                }
+                
+            case KCMD_DRAW_PATH:
+                {
+                if ((currentCommand & 0x00010000)) 
+                    {
+                    idoStroke = VG_TRUE;
+                    }
+                
+                if ((currentCommand & 0x00020000))
+                    {
+                    idoFill = VG_TRUE;
+                    }
+                TUint16 offset = aOffsetVector->DerefInt16L(lOffsetIx * sizeof(TUint16));
+
+                TDereferencer section = GetCommandSectionL(offset, aIconData, aNVGVersion);
+
+                DrawPathL(&section);
+                
+                break;
+                }
+                
+            case KCMD_SET_TRANSFORMATION:
+                {
+                SetTransformL(aCommandSection, transVal, lCurrentPathMatrix);
+                aCommandSection->SkipL(transVal * sizeof(TUint32));
+                break;
+                }
+                
+            case KCMD_SET_STROKE_PAINT:
+                {
+                iStrokeAlpha = (currentCommand & 0x00ff0000) >> 16;
+                TUint16 offset = aOffsetVector->DerefInt16L(lOffsetIx * sizeof(TUint16));
+
+                TDereferencer section = GetCommandSectionL(offset, aIconData, aNVGVersion);
+
+                SetStrokePaintL(&section);
+                
+                break;
+                }
+
+            case KCMD_SET_STROKE_WIDTH:
+                {
+                TReal32 lStrokeWidth;
+                aCommandSection->SkipL(sizeof(TUint32));
+                
+                /*
+                 * check for alignment and copy data if not aligned, else directly convert
+                 * version 2 or above guarantees that is always word aligned
+                 */
+                TUint8 * cptr = aCommandSection->DerefInt8ArrayL(sizeof(TReal32), 0); 
+                if (aNVGVersion < KVersion2 && !IsAligned4(cptr))
+                    {
+                    
+                    Mem::Copy(reinterpret_cast<void *>(&lStrokeWidth),
+                              reinterpret_cast<void *>(cptr), sizeof(lStrokeWidth));
+                    }
+                else
+                    {
+                    lStrokeWidth = aCommandSection->DerefReal32L();
+                    }
+                
+                COND_COM_OC(iInternal->iCreatingNVGIcon,
+                        CSICON(iInternal->iCurrentNVGIcon)->AddSetStrokeWidthCommandL(lStrokeWidth),
+                        vgSetf(VG_STROKE_LINE_WIDTH, lStrokeWidth));
+                break;
+                }
+                
+            case KCMD_SET_STROKE_MITER_LIMIT:
+                {
+                TReal32 lMiterLimit;
+                aCommandSection->SkipL(sizeof(TUint32));
+
+                /*
+                 * check for alignment and copy data if not aligned, else directly convert
+                 * version 2 or above guarantees that is always word aligned
+                 */
+                TUint8 * cptr = aCommandSection->DerefInt8ArrayL(sizeof(TReal32), 0); 
+
+                if (aNVGVersion < KVersion2 && !IsAligned4(cptr))
+                    {
+                    Mem::Copy(reinterpret_cast<void *>(&lMiterLimit),
+                              reinterpret_cast<void *>(cptr), sizeof(lMiterLimit));
+                    }
+                else
+                    {
+                    lMiterLimit = aCommandSection->DerefReal32L();
+                    }
+                
+                COND_COM_OC(iInternal->iCreatingNVGIcon,
+                        CSICON(iInternal->iCurrentNVGIcon)->AddSetStrokeMiterLimitCommandL(lMiterLimit),
+                        vgSetf(VG_STROKE_MITER_LIMIT, lMiterLimit));
+                
+                break;
+                }
+                
+            case KCMD_SET_STROKE_LINE_JOIN_CAP:
+                {
+                TUint8 lJoinType =(currentCommand & 0x0000ff00)>>8;
+                TUint8 lCapType = (currentCommand & 0x000000ff);
+                
+                VGCapStyle capStyle;
+                switch(lCapType)
+                    {
+                    case KCAP_SQUARE:
+                        capStyle = VG_CAP_SQUARE;
+                        break;
+                    case KCAP_ROUND:
+                        capStyle = VG_CAP_ROUND;
+                        break;
+                    case KCAP_BUTT:
+                    default:
+                        capStyle = VG_CAP_BUTT;
+                        break;
+                    }
+   
+                VGJoinStyle lineJoinStyle;
+                switch(lJoinType)
+                    {
+                    case KLINE_JOIN_BEVEL:
+                        lineJoinStyle = VG_JOIN_BEVEL;
+                        break;
+                    case KLINE_JOIN_ROUND:
+                        lineJoinStyle = VG_JOIN_ROUND;
+                        break;
+                    case KLINE_JOIN_MITER:
+                    default:
+                        lineJoinStyle = VG_JOIN_MITER;
+                        break;
+                    }
+                
+                COND_COM_OC(iInternal->iCreatingNVGIcon,
+                        CSICON(iInternal->iCurrentNVGIcon)->AddStrokeLineJoinCapCommandL(capStyle, lineJoinStyle),
+                        vgSeti(VG_STROKE_CAP_STYLE, capStyle);
+                        vgSeti(VG_STROKE_JOIN_STYLE, lineJoinStyle););
+                break;
+                }
+                
+            default:
+                {
+                User::Leave(KErrCorrupt);
+                break;
+                }
+            }
+        
+        // go to the next command
+        aCommandSection->SkipL(sizeof(TUint32));
+        }
+    }
+
+EXPORT_C void CNvgEngine::SetPreserveAspectRatio(
+        TNvgAlignStatusType aPreserveAspectSetting, 
+        TNvgMeetOrSliceType aSmilFitSetting)
+    {
+    iPreserveAspectSetting = aPreserveAspectSetting;
+    iSmilFitSetting = aSmilFitSetting;
+    }
+
+EXPORT_C void CNvgEngine::SetBackgroundColor(TUint32 aRGBA8888Color)
+    {
+    iBackgroundColor = aRGBA8888Color;
+    }
+
+TInt CNvgEngine::SetFillPaintL(TDereferencer * aIconData)
+    {
+    COND_COM_OC_OOC(register int drawingMode = iInternal->iCreatingNVGIcon);
+    
+    TUint32 lCommonData  = aIconData->DerefInt32L();
+    TUint lPaintType     = lCommonData & 0x07;
+    TUint16 lSpecifcData = (lCommonData >> 16) & 0xff;
+    
+    switch (lPaintType)
+        {
+        case KPAINT_LGRAD:
+            {
+            iGradPaintFill = iPaintFill;
+            
+            COND_COM_OC_OOC(
+            if (iInternal->iCreatingNVGIcon)
+                {
+                // CNVGCSIcon will destroy the paint handle
+                iGradPaintFill = vgCreatePaint();
+                if (iGradPaintFill == VG_INVALID_HANDLE)
+                    {
+                    User::LeaveIfError(CNvgEngine::OpenVGErrorToSymbianError(vgGetError()));
+                    }
+                });
+
+            // gradient data, the data will be word aligned
+            TReal32* lGradData = (TReal32*)aIconData->DerefInt8ArrayL(4 * sizeof(VGfloat), sizeof(TUint32));
+            
+            vgSetParameteri(iGradPaintFill, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT);
+            vgSetParameterfv(iGradPaintFill, VG_PAINT_LINEAR_GRADIENT, 4, lGradData);
+            vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER);
+            
+            if (lSpecifcData & 0x1)
+                {
+                TReal32* lGradMatrix1 = (TReal32*) aIconData->DerefInt8ArrayL(6 * sizeof (VGfloat),
+                                                    KNVG_PAINTSECTION_LINEARGRAD_TRANSFORM_OFFSET);
+                
+                TReal32 lGradMatrix[9] = {lGradMatrix1[0], lGradMatrix1[3], 0.0f,  
+                        lGradMatrix1[1], lGradMatrix1[4], 0.0f,
+                        lGradMatrix1[2], lGradMatrix1[5], 1.0f};
+                
+                COND_COM_OC(drawingMode,
+                        CSICON(iInternal->iCurrentNVGIcon)->AddLinearGradientCommandL(4, lGradData, lGradMatrix, iGradPaintFill),
+                        vgLoadMatrix(lGradMatrix););
+                }
+            else
+                {
+                COND_COM_OC(drawingMode,
+                        CSICON(iInternal->iCurrentNVGIcon)->AddLinearGradientCommandL(4, lGradData, (VGfloat*)KIdentityMatrix, iGradPaintFill),
+                        vgLoadIdentity());
+                }
+            
+            COND_COM_OC(drawingMode, ;,
+                     vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE));
+            
+            break;
+            }
+            
+        case KPAINT_RGRAD:
+            {
+            // gradient data, the data will be word aligned
+            TReal32* lGradData = (TReal32*)aIconData->DerefInt8ArrayL(5 * sizeof(VGfloat), sizeof(TUint32));
+            iGradPaintFill = iPaintFill;
+            
+            COND_COM_OC_OOC(
+            if (iInternal->iCreatingNVGIcon)
+                {
+                iGradPaintFill = vgCreatePaint();
+                if (iGradPaintFill == VG_INVALID_HANDLE)
+                    {
+                    User::LeaveIfError(CNvgEngine::OpenVGErrorToSymbianError(vgGetError()));
+                    }                
+                });
+
+            vgSetParameteri(iGradPaintFill, VG_PAINT_TYPE, VG_PAINT_TYPE_RADIAL_GRADIENT);
+            vgSetParameterfv(iGradPaintFill, VG_PAINT_RADIAL_GRADIENT, 5, lGradData);
+            vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER);
+
+
+            if (lSpecifcData & 0x1)
+                {
+                TReal32* lGradMatrix1 = (TReal32*)aIconData->DerefInt8ArrayL(6 * sizeof (VGfloat),
+                                                   KNVG_PAINTSECTION_RADIALGRAD_TRANSFORM_OFFSET);
+                
+                TReal32 lGradMatrix[9] = {lGradMatrix1[0], lGradMatrix1[3], 0.0f,  
+                        lGradMatrix1[1], lGradMatrix1[4], 0.0f,
+                        lGradMatrix1[2], lGradMatrix1[5], 1.0f};
+                
+                COND_COM_OC(drawingMode,
+                        CSICON(iInternal->iCurrentNVGIcon)->AddRadialGradientCommandL(5, lGradData, lGradMatrix, iGradPaintFill),
+                        vgLoadMatrix(lGradMatrix));
+                }
+            else
+                {
+                COND_COM_OC(drawingMode,
+                        CSICON(iInternal->iCurrentNVGIcon)->AddRadialGradientCommandL(5, lGradData, (VGfloat*)KIdentityMatrix, iGradPaintFill),
+                        vgLoadIdentity());
+                }
+            
+            COND_COM_OC(drawingMode, ;,
+                    vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE));
+            break;
+            }
+            
+        case KPAINT_FLAT:
+            {
+            TUint32 lRgba = aIconData->DerefInt32L(KNVG_RGBA_OFS);
+
+            lRgba = (lRgba & 0xffffff00) | iFillAlpha;
+            
+            COND_COM_OC(drawingMode,
+                    CSICON(iInternal->iCurrentNVGIcon)->AddSetColorCommandL(lRgba),
+                    vgSetParameteri(iPaintFill, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+                    vgSetColor(iPaintFill, lRgba));            
+            break;
+            }
+            
+        default:
+            {
+            User::Leave(KErrCorrupt);
+            break;
+            }
+        }
+    return KErrNone;
+    }
+
+TInt CNvgEngine::SetColorRampL(TDereferencer * aIconData)
+    {
+    TUint32 lCommonData = aIconData->DerefInt32L();
+    
+    TInt lStopCount = (lCommonData >> 16) & 0x00ff;
+    TReal32* lStopData = (TReal32*)aIconData->DerefInt8ArrayL(lStopCount * 5 * sizeof(TReal32), sizeof(TUint32));
+    
+    VGfloat * colorRamps = new (ELeave) VGfloat[lStopCount * 5];
+    CleanupStack::PushL(TCleanupItem(CleanupArray, colorRamps));
+        
+    if (iFillAlpha == 0xff)
+        {
+        vgSetParameteri(iGradPaintFill, VG_PAINT_COLOR_RAMP_SPREAD_MODE, VG_COLOR_RAMP_SPREAD_PAD);
+        vgSetParameterfv(iGradPaintFill, VG_PAINT_COLOR_RAMP_STOPS, lStopCount * 5, lStopData);
+        }
+    else
+        {
+        // Copy color ramps and modify alpha
+        memcpy(colorRamps, lStopData, lStopCount * 5 * sizeof(VGfloat));
+        
+        VGfloat lAlphaInFloat = iFillAlpha * (1.0f/255.0f);
+        VGfloat* lAlphaValue  = &colorRamps[4];
+        
+        for (int i=0; i<lStopCount; i++)
+            {
+            *lAlphaValue *= lAlphaInFloat;
+            lAlphaValue += 5;
+            }
+        
+        vgSetParameteri(iGradPaintFill, VG_PAINT_COLOR_RAMP_SPREAD_MODE, VG_COLOR_RAMP_SPREAD_PAD);
+        vgSetParameterfv(iGradPaintFill, VG_PAINT_COLOR_RAMP_STOPS, lStopCount * 5, colorRamps);       
+        }
+    
+    CleanupStack::PopAndDestroy();
+    return KErrNone;
+    }
+
+void CNvgEngine::SetStrokePaintL(TDereferencer * aIconData)
+    {
+    COND_COM_OC_OOC(register int drawingMode = iInternal->iCreatingNVGIcon;);
+    
+    TUint32 lCommonData  = aIconData->DerefInt32L();
+    TUint lStrokeType    = lCommonData & 0x07;
+    TUint16 lSpecifcData = (lCommonData >> 16) & 0xff;
+        
+    switch (lStrokeType)
+        {
+        case KSTROKE_LGRAD:
+            {
+            iGradPaintStroke = iPaintStroke;
+            
+            COND_COM_OC_OOC(
+            if (iInternal->iCreatingNVGIcon)
+                {
+                iGradPaintStroke = vgCreatePaint();
+                User::LeaveIfNull((TAny *)iGradPaintStroke);
+                });
+
+            // gradient data, the data will be word aligned
+            TReal32* lGradData = (TReal32*)aIconData->DerefInt8ArrayL(4 * sizeof(VGfloat), sizeof(TUint32));
+            
+            COND_COM_OC(drawingMode, ;,
+                    vgSetParameteri( iGradPaintStroke, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT );
+                    vgSetParameterfv( iGradPaintStroke, VG_PAINT_LINEAR_GRADIENT, 4, lGradData);                
+                    vgSeti(VG_MATRIX_MODE, VG_MATRIX_STROKE_PAINT_TO_USER));
+                        
+            if (lSpecifcData & 0x1)
+                {
+                TReal32* lGradMatrix1 = (TReal32*)aIconData->DerefInt8ArrayL(6 * sizeof(VGfloat),
+                                                                             4 + 4 * sizeof(VGfloat));
+                TReal32 lGradMatrix[9] = {lGradMatrix1[0], lGradMatrix1[3], 0.0f,  
+                        lGradMatrix1[1], lGradMatrix1[4], 0.0f,
+                        lGradMatrix1[2], lGradMatrix1[5], 1.0f};
+                
+                COND_COM_OC(drawingMode,
+                        CSICON(iInternal->iCurrentNVGIcon)->AddStrokeLinearGradientCommandL(4, lGradData, lGradMatrix, iGradPaintStroke),
+                        vgLoadMatrix(lGradMatrix));                
+                }
+            else
+                {
+                COND_COM_OC(drawingMode,
+                        CSICON(iInternal->iCurrentNVGIcon)->AddStrokeLinearGradientCommandL(4, lGradData, (VGfloat*)KIdentityMatrix, iGradPaintStroke),
+                        vgLoadIdentity());                
+                }
+            vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+            break;
+            }
+
+        case KSTROKE_RGRAD:
+            {
+            iGradPaintStroke = iPaintStroke;
+            
+            COND_COM_OC_OOC(
+            if (iInternal->iCreatingNVGIcon)
+                {
+                iGradPaintStroke = vgCreatePaint();
+                User::LeaveIfNull((TAny *)iGradPaintStroke);
+                });
+            
+            // gradient data, the data will be word aligned
+            TReal32* lGradData = (TReal32*)aIconData->DerefInt8ArrayL(5 * sizeof(VGfloat), sizeof(TUint32));
+            
+            COND_COM_OC(drawingMode, ;,
+                     vgSetParameteri( iGradPaintStroke, VG_PAINT_TYPE, VG_PAINT_TYPE_RADIAL_GRADIENT );
+                     vgSetParameterfv( iGradPaintStroke, VG_PAINT_RADIAL_GRADIENT, 5, lGradData);            
+                     vgSeti(VG_MATRIX_MODE, VG_MATRIX_STROKE_PAINT_TO_USER));
+            
+            if (lSpecifcData & 0x1)
+                {
+                TReal32* lGradMatrix1 = (TReal32*)aIconData->DerefInt8ArrayL(6 * sizeof(VGfloat),
+                                                                             4 + 5 * sizeof(VGfloat));
+                TReal32 lGradMatrix[9] = {lGradMatrix1[0], lGradMatrix1[3], 0.0f,  
+                        lGradMatrix1[1], lGradMatrix1[4], 0.0f,
+                        lGradMatrix1[2], lGradMatrix1[5], 1.0f};
+                
+                COND_COM_OC(drawingMode,
+                        CSICON(iInternal->iCurrentNVGIcon)->AddStrokeRadialGradientCommandL(4, lGradData, lGradMatrix, iGradPaintStroke),
+                        vgLoadMatrix(lGradMatrix));                
+                }
+            else
+                {
+                COND_COM_OC(drawingMode,
+                        CSICON(iInternal->iCurrentNVGIcon)->AddStrokeRadialGradientCommandL(4, lGradData, (VGfloat*)KIdentityMatrix, iGradPaintStroke),
+                        vgLoadIdentity());
+                }
+            vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+            break;
+            }
+            
+        case KSTROKE_COLOR_RAMP:
+            {
+            TInt lStopCount = lSpecifcData;
+            TReal32* lStopData = (TReal32*) aIconData->DerefInt8ArrayL(lStopCount * 5 * sizeof(VGfloat), 4);
+            
+            if (iStrokeAlpha == 0xff)
+                {
+                 vgSetParameteri(iGradPaintStroke, VG_PAINT_COLOR_RAMP_SPREAD_MODE, VG_COLOR_RAMP_SPREAD_PAD);
+                 vgSetParameterfv(iGradPaintStroke, VG_PAINT_COLOR_RAMP_STOPS, lStopCount*5, lStopData);                
+                }
+            else
+                {
+                VGfloat * colorRamps = new (ELeave) VGfloat[lStopCount * 5];
+                CleanupStack::PushL(TCleanupItem(CleanupArray, colorRamps));
+
+                memcpy(colorRamps, lStopData, lStopCount * 5 * sizeof(VGfloat));
+                
+                VGfloat lAlphaInFloat = iStrokeAlpha * (1.0f/255.0f);
+                VGfloat* lAlphaValue  = &colorRamps[4];
+                
+                for (int i=0; i<lStopCount; i++)
+                    {
+                    *lAlphaValue *= lAlphaInFloat;
+                    lAlphaValue += 5;
+                    }
+                
+                vgSetParameteri(iGradPaintStroke, VG_PAINT_COLOR_RAMP_SPREAD_MODE, VG_COLOR_RAMP_SPREAD_PAD);
+                vgSetParameterfv(iGradPaintStroke, VG_PAINT_COLOR_RAMP_STOPS, lStopCount * 5, colorRamps);
+                CleanupStack::PopAndDestroy();
+                }
+            break;
+            } 
+            
+        default:
+            {
+            TUint32 lRgba = aIconData->DerefInt32L(KNVG_RGBA_OFS);
+            lRgba = (lRgba & 0xffffff00)|iStrokeAlpha; // replace alpha
+            
+            COND_COM_OC(drawingMode,
+                    CSICON(iInternal->iCurrentNVGIcon)->AddStrokeSetColorCommandL(lRgba),
+                    vgSetParameteri( iPaintStroke, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR );
+                    vgSetColor(iPaintStroke, lRgba));            
+            break;
+            }
+        }
+    }
+
+void CNvgEngine::DrawPathL(TDereferencer * aIconData)
+    {
+    TInt numSegments = aIconData->DerefInt16L();
+    const VGubyte * pathSegments  = aIconData->DerefInt8ArrayL(numSegments, sizeof(TUint16));
+    
+    /*
+     * verify that what we got is proper data
+     * for that calculate the path co-ordinate length
+     * and check that the path data does not overflow
+     */    
+    TInt coordinateCount = 0;
+    for (TInt i = 0; i < numSegments; ++i)
+        {
+        switch (pathSegments[i])
+            {
+            case VG_HLINE_TO:
+            case VG_VLINE_TO:
+                coordinateCount += 1;
+                break;
+            case VG_MOVE_TO:
+            case VG_LINE_TO:
+            case VG_SQUAD_TO:
+                coordinateCount += 2;
+                break;                
+            case VG_QUAD_TO:
+            case VG_SCUBIC_TO:
+                coordinateCount += 4;
+                break;
+            case VG_SCCWARC_TO:
+            case VG_SCWARC_TO:
+            case VG_LCCWARC_TO:
+            case VG_LCWARC_TO:
+                coordinateCount += 5;
+                break;
+            case VG_CUBIC_TO:
+                coordinateCount += 6;
+                break;
+            default:
+                break;
+            }
+        }
+
+    // this one is just to check the alignment
+    TUint8* pathData = aIconData->DerefInt8ArrayL(sizeof(TUint32), sizeof(TUint16) + numSegments);
+    
+    /*
+     * path data need to be word aligned
+     * alignment are done according to the path format
+     */
+    TUint sizeofpathdata = sizeof(TUint32);
+    TUint alignSkip = 0;
+    TUint8 * alignedPtr = 0;
+    if (iLastPathDataType == ESixteenBitEncoding)
+        {
+        alignedPtr = Align2(pathData);
+        sizeofpathdata = sizeof(TUint16);
+        }
+    else if (iLastPathDataType == EThirtyTwoBitEncoding)
+        {        
+        alignedPtr = Align4(pathData);
+        }
+    else
+        {
+        User::Leave(KErrCorrupt); // no other path data type is supported
+        }
+    
+    alignSkip = alignedPtr - pathData; 
+    
+    /*
+     * check to see whether we have enough path data
+     */
+    aIconData->IsSafeL(coordinateCount * sizeofpathdata + alignSkip, sizeof(TUint16) + numSegments);
+    
+    pathData = alignedPtr;
+    
+    VGint paintMode = (idoFill ? VG_FILL_PATH : 0)|(idoStroke ? VG_STROKE_PATH : 0);
+    if (paintMode == 0)
+        {
+        paintMode = VG_FILL_PATH;
+        }
+    
+    COND_COM_OC(iInternal->iCreatingNVGIcon,
+            {
+                VGPath path = CreatePath();
+                
+                if (path != VG_INVALID_HANDLE)
+                    {
+                    vgAppendPathData(path, numSegments, pathSegments, pathData);
+                    }
+                else
+                    {
+                    CSICON(iInternal->iCurrentNVGIcon)->AddPathDataL(numSegments, pathSegments, pathData);
+                    }        
+                CSICON(iInternal->iCurrentNVGIcon)->AddDrawPathCommandL(path, paintMode);
+            }, 
+            {
+                vgClearPath(iPath, VG_PATH_CAPABILITY_APPEND_TO);
+                
+                vgAppendPathData(iPath, numSegments, pathSegments, pathData);
+                vgDrawPath(iPath, paintMode);
+            });
+    
+    idoStroke   = VG_FALSE;
+    idoFill     = VG_FALSE;
+    }
+
+#ifdef    OPENVG_OBJECT_CACHING
+VGPath CNvgEngine::CreatePath()
+    {
+    VGPath path = VG_INVALID_HANDLE;
+    switch (iLastPathDataType)
+        {
+        case EEightBitEncoding:
+            {
+            path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
+            VG_PATH_DATATYPE_S_16, 1.0f/2.0f, 0.0f, 0, 0,
+            VG_PATH_CAPABILITY_APPEND_TO);           
+            }
+            break;
+            
+        case ESixteenBitEncoding:
+            {
+            path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
+            VG_PATH_DATATYPE_S_16, 1.0f/16.0f, 0.0f, 0, 0,
+            VG_PATH_CAPABILITY_APPEND_TO);            
+            }
+            break;
+           
+        case EThirtyTwoBitEncoding:
+            {
+            path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
+            VG_PATH_DATATYPE_S_32, 1.0f/65536.0f, 0.0f, 0, 0,
+            VG_PATH_CAPABILITY_APPEND_TO);            
+            }
+            break;
+    
+        default:
+            {
+        
+            }
+           break;
+           }
+    return path;
+    }
+#endif
+
+void CNvgEngine::SetTransformL(TDereferencer * aIconData, TUint32 & aCounter, const VGfloat* aCurrentMatrix)
+    {
+    
+    COND_COM_OC(iInternal->iCreatingNVGIcon, ;,
+             vgLoadMatrix(aCurrentMatrix));
+    
+    TUint32 lCommonData    = aIconData->DerefInt32L();
+    TUint32 lTransformType = (lCommonData & 0x00ff0000)>>16 ;
+    
+    VGfloat matrixTemp[9] = {
+            1.0f, 0.0f, 0.0f,
+            0.0f, 1.0f, 0.0f,
+            0.0f, 0.0f, 1.0f };   
+    
+    aCounter = 0;
+    
+    if (lTransformType != 1)
+        {
+        if (lTransformType == KTRANSFORM_COMPLETE)
+            {
+            matrixTemp[0] = aIconData->DerefReal32L((++aCounter) * sizeof (VGfloat));
+            matrixTemp[4] = aIconData->DerefReal32L((++aCounter) * sizeof (VGfloat));
+            matrixTemp[3] = aIconData->DerefReal32L((++aCounter) * sizeof (VGfloat));
+            matrixTemp[1] = aIconData->DerefReal32L((++aCounter) * sizeof (VGfloat));
+            matrixTemp[6] = aIconData->DerefReal32L((++aCounter) * sizeof (VGfloat));
+            matrixTemp[7] = aIconData->DerefReal32L((++aCounter) * sizeof (VGfloat));
+            }
+        else
+            {
+            if (lTransformType & KTRANSFORM_ROTATION)
+                {
+                //vgScale
+                matrixTemp[0] = aIconData->DerefReal32L((++aCounter) * sizeof (VGfloat));
+                matrixTemp[4] = aIconData->DerefReal32L((++aCounter) * sizeof (VGfloat));
+                
+                //vgShear
+                matrixTemp[3] = aIconData->DerefReal32L((++aCounter) * sizeof (VGfloat));
+                matrixTemp[1] = aIconData->DerefReal32L((++aCounter) * sizeof (VGfloat));
+                }
+            else
+                {
+                if (lTransformType & KTRANSFORM_SCALING)
+                    {
+                    //vgScale
+                    matrixTemp[0] = aIconData->DerefReal32L((++aCounter) * sizeof (VGfloat));
+                    matrixTemp[4] = aIconData->DerefReal32L((++aCounter) * sizeof (VGfloat));
+                    }
+                
+                if (lTransformType & KTRANSFORM_SHEARING)
+                    {
+                    //vgShear
+                    matrixTemp[3] = aIconData->DerefReal32L((++aCounter) * sizeof (VGfloat));
+                    matrixTemp[1] = aIconData->DerefReal32L((++aCounter) * sizeof (VGfloat));
+                    }
+                }
+            
+            if (lTransformType & KTRANSFORM_TRANSLATION)
+                {
+                //vgTranslate
+                matrixTemp[6] = aIconData->DerefReal32L((++aCounter) * sizeof (VGfloat));
+                matrixTemp[7] = aIconData->DerefReal32L((++aCounter) * sizeof (VGfloat));
+                }
+            }
+        
+        COND_COM_OC(iInternal->iCreatingNVGIcon,
+                CSICON(iInternal->iCurrentNVGIcon)->AddSetTransformCommandL(matrixTemp, 1),
+                vgMultMatrix(matrixTemp));        
+        }
+    else
+        {
+        COND_COM_OC(iInternal->iCreatingNVGIcon,
+                CSICON(iInternal->iCurrentNVGIcon)->AddSetTransformCommandL(matrixTemp, 0), ;);
+        }
+    }
+
+void CNvgEngine::GenerateMask(CFbsBitmap* aMask)
+    {
+    if (!aMask || aMask->SizeInPixels() != iCurrentBufferSize)
+        {
+        return;
+        }
+    
+    const TDisplayMode KMaskDisplayMode = aMask->DisplayMode();
+    
+    if (KMaskDisplayMode != EGray256 && KMaskDisplayMode != EGray2)
+        {
+        return;
+        }
+    
+    const TInt KOriginalFilterMasks = vgGeti(VG_FILTER_CHANNEL_MASK);
+    const TInt KStride = CFbsBitmap::ScanLineLength(iCurrentBufferSize.iWidth, KMaskDisplayMode);
+    
+    // Change to get alpha values from OpenVG
+    vgSeti(VG_FILTER_CHANNEL_MASK, VG_ALPHA);
+    
+    VGImageFormat format = (KMaskDisplayMode == EGray256) ? VG_A_8 : VG_BW_1;
+    
+    aMask->LockHeap();
+
+    /*
+     * Get data address of last line and move upwards (negative stride)
+     * OpenVG uses Cartesian coordinate system and Symbian uses Screen coordinate system.
+     */
+    TUint* data = (TUint*)((TUint)aMask->DataAddress() + (KStride * (iCurrentBufferSize.iHeight - 1 )));
+    
+    vgReadPixels(data, -KStride, format, 0, 0,
+            iCurrentBufferSize.iWidth, iCurrentBufferSize.iHeight);
+    aMask->UnlockHeap();
+    
+    // Set back the original filter-masks
+    vgSeti(VG_FILTER_CHANNEL_MASK, KOriginalFilterMasks);
+    }
+
+void CNvgEngine::ClearBackground()
+    {
+    TUint32 rgba = (iBackgroundColor << 8) | (iBackgroundColor >> 24);
+    TInt32 r, g, b, a;
+    r = (TInt)((rgba & 0xFF000000) >> 24);
+    g = (TInt)((rgba & 0x00FF0000) >> 16);
+    b = (TInt)((rgba & 0x0000FF00) >> 8);
+    a = (TInt)(rgba & 0x000000FF);
+    
+    r += r >> 7; g += g >> 7; b += b >> 7; a += a >> 7;
+    
+    const VGfloat KInverse255 =  1.0f/256.0f;
+    const VGfloat clearColor[4] = { (KInverse255 * VGfloat (r)),
+            (KInverse255 * VGfloat (g)),
+            (KInverse255 * VGfloat (b)),
+            (KInverse255 * VGfloat (a)) };
+    
+    vgSeti(VG_SCISSORING, VG_FALSE);
+    vgSetfv(VG_CLEAR_COLOR, 4, clearColor);
+    vgClear(0, 0, iCurrentBufferSize.iWidth, iCurrentBufferSize.iHeight);
+    vgSeti(VG_SCISSORING, VG_TRUE);
+    }
+
+TBool CNvgEngine::IsIdentity(VGfloat array[])
+    {
+    return ((array[0] == 1.0f && array[4] == 1.0f && array[8] == 1.0f)&& 
+            (array[1] == 0.0f && array[2] == 0.0f && array[3] == 0.0f &&
+             array[5] == 0.0f && array[6] == 0.0f && array[7] == 0.0f));
+    }
+
+TInt CNvgEngine::OpenVGErrorToSymbianError( TInt aError )
+    {
+    TInt error = KErrNone;
+    switch (aError)
+        {            
+        case VGU_OUT_OF_MEMORY_ERROR:
+        case VG_OUT_OF_MEMORY_ERROR:
+            {
+            error = KErrNoMemory;   
+            break;
+            }
+            
+        case VG_ILLEGAL_ARGUMENT_ERROR:
+        case VGU_ILLEGAL_ARGUMENT_ERROR:
+            {
+            error = KErrArgument; 
+            break;
+            }
+            
+        case VG_UNSUPPORTED_PATH_FORMAT_ERROR:
+        case VG_UNSUPPORTED_IMAGE_FORMAT_ERROR:
+            {
+            error = KErrNotSupported; 
+            break;
+            }
+            
+        case VG_IMAGE_IN_USE_ERROR:
+            {
+            error = KErrInUse; 
+            break;
+            }
+            
+        case VG_BAD_HANDLE_ERROR:
+        case VGU_BAD_HANDLE_ERROR:
+            {
+            error = KErrBadHandle;
+            break;
+            }
+            
+        case VG_PATH_CAPABILITY_ERROR:
+        case VGU_PATH_CAPABILITY_ERROR:
+        case VGU_BAD_WARP_ERROR:
+            {
+            error = KErrUnknown;
+            break;
+            }
+            
+        case VG_NO_CONTEXT_ERROR:
+            {
+            error = KErrNotReady;
+            break;
+            }
+        
+        default:
+            {
+            error = KErrUnknown; 
+            }
+        }
+    
+    return error;
+    }
+
+void CNvgEngine::UpdateClientMatrices()
+    {
+    iMatrixMode = vgGeti(VG_MATRIX_MODE);
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+    vgGetMatrix(iPathMatrix);
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+    vgGetMatrix(iImageMatrix);
+    vgSeti(VG_MATRIX_MODE, iMatrixMode);
+    }
+
+void CNvgEngine::RestoreClientMatrices()
+    {
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+    vgLoadMatrix(iPathMatrix);
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+    vgLoadMatrix(iImageMatrix);
+    vgSeti(VG_MATRIX_MODE, iMatrixMode);
+    }   
+    
+TPoint CNvgEngine::GetTranslatedPoint(VGfloat aTRMatrix[9], TPoint aPoint)
+    {
+    TPoint trPoint;
+    
+    trPoint.iX = aTRMatrix[0] * aPoint.iX + aTRMatrix[3] * aPoint.iY + aTRMatrix[6];
+    trPoint.iY = aTRMatrix[1] * aPoint.iX + aTRMatrix[4] * aPoint.iY + aTRMatrix[7];
+    
+    return trPoint;
+    }
+
+VGfloat CNvgEngine::MinVal4(VGfloat x1, VGfloat x2, VGfloat x3, VGfloat x4 )
+    {
+    VGfloat min = x1;
+    
+    if (min > x2)
+        {
+        min = x2;
+        }
+    if (min > x3)
+        {
+        min = x3;
+        }
+    if (min > x4)
+        {
+        min = x4;
+        }
+    
+    return min;
+    }
+
+VGfloat CNvgEngine::MaxVal4(VGfloat x1, VGfloat x2, VGfloat x3, VGfloat x4 )
+    {
+    VGfloat max = x1;
+    
+    if (max < x2)
+        {
+        max = x2;
+        }
+    if (max < x3)
+        {
+        max = x3;
+        }
+    if (max < x4)
+        {
+        max = x4;
+        }
+    
+    return max;
+    }
+