graphicsdeviceinterface/directgdiadaptation/hwsrc/vgengine.cpp
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graphicsdeviceinterface/directgdiadaptation/hwsrc/vgengine.cpp	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,3820 @@
+// Copyright (c) 2007-2009 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:
+// Unless stated otherwise, all co-ordinates are recorded and calculated using 
+// Symbian graphics format: origin at top left of image, 'y' increasing towards bottom
+// of image. Note that OpenVG places the origin at an image's bottom left corner, with
+// 'y' increasing towards the top of the image. 
+// 
+//
+
+#include "vgengine.h"
+#include "directgdiadapter.h"
+#include "directgdidriverimpl.h"
+#include "directgdiimagetargetimpl.h"
+#include "directgdiimagesourceimpl.h"
+#include "confighelper.h"
+#include <graphics/directgdiimagetarget.h>
+#include <graphics/directgdidrawablesource.h>
+#include <fbs.h>
+#include <e32cmn.h>
+#include <e32math.h>
+#include <s32strm.h>
+#include <pixelformats.h>
+#include <bitdraworigin.h>
+#include <bitdrawinterfaceid.h>
+
+#include "blendingalgorithms.inl"
+
+/**
+Pre-calculation for normalising a 0-255 colour channel to 0..1.
+*/
+const VGfloat KColorConversion = 1.0f/255.0f;
+
+
+inline TInt Scale(TInt aValue,TInt aNum,TInt aDen)
+	{
+	if (aNum==aDen)
+		return aValue;
+	TInt64 result(aValue);
+	result=(result*aNum+(aDen/2))/aDen;
+	return I64INT(result);
+	}
+
+/**
+Maps TDisplayMode onto a supported VGImageFormat. Only compatible formats are returned,
+anything else results in VG_IMAGE_FORMAT_INVALID being returned.
+
+@param 	aDisplayMode Mode to convert from.
+
+@return The VGImageFormat which matches the specified TDisplayMode pixel format exactly.
+		If no exact match exists, then VG_IMAGE_FORMAT_INVALID is returned.
+ */
+static VGImageFormat MapToVgDisplayMode(TDisplayMode aDisplayMode)
+	{
+	switch(aDisplayMode)
+		{
+	case ENone:
+		return VG_IMAGE_FORMAT_INVALID;
+	case EGray2:
+		return VG_BW_1;
+	case EGray4: 
+	case EGray16:
+		return VG_IMAGE_FORMAT_INVALID;
+	case EGray256:
+		return VG_sL_8;
+	case EColor16:
+	case EColor256:
+	case EColor4K:
+		return VG_IMAGE_FORMAT_INVALID;
+	case EColor64K:
+		return VG_sRGB_565;
+	case EColor16M:
+	case ERgb:
+		return VG_IMAGE_FORMAT_INVALID;
+	case EColor16MU:
+		return VG_sXRGB_8888;
+	case EColor16MA:
+		return VG_sARGB_8888;
+	case EColor16MAP:
+		return VG_sARGB_8888_PRE;
+	case EColorLast:
+		return VG_IMAGE_FORMAT_INVALID;
+		}
+	
+	return VG_IMAGE_FORMAT_INVALID;
+	}
+
+/**
+Destructor
+ */
+CVgEngine::~CVgEngine()
+	{
+	iRegionManager.Close();
+	
+	if (iBrushPatternUser != VG_INVALID_HANDLE)	
+		vgDestroyImage(iBrushPatternUser);		
+		
+	if (iBrushPatternStandard != VG_INVALID_HANDLE)
+		vgDestroyImage(iBrushPatternStandard);		
+	
+	if (iBrushPatternStandardRegion != VG_INVALID_HANDLE)
+		vgDestroyImage(iBrushPatternStandardRegion);		
+	
+	if (iBrushPatternNonZeroOrigin != VG_INVALID_HANDLE)
+		vgDestroyImage(iBrushPatternNonZeroOrigin);	
+	
+	User::Free(iPathCommands);	
+	User::Free(iPathCoords);
+	
+	Deactivate();
+	}
+
+/**
+Constructor
+ */
+CVgEngine::CVgEngine(CDirectGdiDriverImpl& aDriver)
+	:iDriver(aDriver),
+	iPen(VG_INVALID_HANDLE),
+	iBrush(VG_INVALID_HANDLE),
+	iClearBrush(VG_INVALID_HANDLE),
+	iVgPath(VG_INVALID_HANDLE),
+	iTextBrush(VG_INVALID_HANDLE),
+	iBrushPatternUser(VG_INVALID_HANDLE),
+	iBrushPatternStandard(VG_INVALID_HANDLE),
+	iBrushPatternStandardRegion(VG_INVALID_HANDLE),
+	iBrushPatternNonZeroOrigin(VG_INVALID_HANDLE)
+	{		
+	// Set the default paint mode for drawing and filling shapes to
+	// just draw the pen and not the brush as default (to match BitGdi)
+	iPaintMode = VG_STROKE_PATH;
+	
+	//cache interface to use every time glyph gets drawn
+	GetInterface(TUid::Uid(KDirectGdiGetGlyphStorageUid), (TAny*&) iFontGlyphImageStorage);
+	}
+
+/**
+Applies the engine's state to OpenVG, re-applying all the VgEngine settings. It is called by 
+Activate() as well as when the engine is being made current. 
+*/
+void CVgEngine::SetVgState()
+	{
+	ResetVgMatrix();
+	vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_NONANTIALIASED);
+	vgSeti(VG_IMAGE_QUALITY, VG_IMAGE_QUALITY_NONANTIALIASED);
+	vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_ROUND);
+	vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
+	vgSetPaint(iPen, VG_STROKE_PATH);
+	vgSetPaint(iBrush, VG_FILL_PATH);
+	SetDrawMode(iDrawMode); 
+	SetPenColor(iPenColor);
+	SetPenStyle(iPenStyle);
+	SetPenSize(iPenSize);
+	SetBrushColor(iBrushColor);
+	SetBrushStyle(iBrushStyle);
+	SetBrushOrigin(iBrushOrigin);
+	vgSetParameteri(iClearBrush, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+	vgSetParameteri(iTextBrush, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+	}
+
+/**
+Binds a rendering target to this OpenVG rendering engine.
+Activates the target, which increments the reference count of target as it can be shared across many 
+DirectGDI contexts.
+
+The rendering target, for this implementation, specifies an Embedded OpenVG rendering surface.
+
+@see MDirectGdiEngine::Activate()
+@see Deactivate()
+
+@panic DGDIAdapter 34, if the passed target has a NULL handle.
+@panic DGDIAdapter 39, if target associated with the handle is NULL.
+ */
+TInt CVgEngine::Activate(RDirectGdiImageTarget& aTarget)
+	{
+	TInt result = KErrNone;
+	GRAPHICS_ASSERT_ALWAYS(aTarget.Handle(), EDirectGdiPanicActivateWithNullHandle);
+	CDirectGdiImageTargetImpl* target = iDriver.GetImageTargetFromHandle(aTarget.Handle());
+	GRAPHICS_ASSERT_ALWAYS(target, EDirectGdiPanicNullTargetActivate);
+	if (target == iRenderingTarget)
+		{
+		return KErrNone;
+		}
+	
+	Deactivate();	
+	
+	iDriver.Activate(target);
+	iRenderingTarget = target;
+	iDriver.SetCurrentEngine(this);
+	iDriver.SetCurrentTarget(target);
+	iSize = iRenderingTarget->Size();
+	iTargetRegion.Clear();
+	iTargetRegion.AddRect(iSize);
+
+	iRegionManager.Initialize(vgGeti(VG_MAX_SCISSOR_RECTS), iSize);
+	
+	// Set the origin to top-left for path and image rendering. iIdentityMatrix is set so that we have a
+	// record of the "identity" transform. After modifying the transform for offsets, rotations, etc, etc
+	// just set to iIdentityMatrix to get back to "normal".
+	//
+	vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+	vgLoadIdentity();
+	vgScale(1, -1);
+	vgTranslate(0,  -iSize.iHeight);
+	vgGetMatrix(iIdentityMatrix);
+	// Set the origin to top-left for image matrix.
+	vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+	vgLoadMatrix(iIdentityMatrix);
+	
+	// Create the path.
+	if (!PreparePath(iVgPath, 1) || (iVgPath == VG_INVALID_HANDLE))
+		result = KErrNoMemory;
+
+	// Create the pen object and set it as the object for stroking (OpenVG equivalent of a pen).
+	if (result == KErrNone)
+		{
+		iPen = vgCreatePaint();
+		if (iPen != VG_INVALID_HANDLE)
+			vgSetPaint(iPen, VG_STROKE_PATH);
+		else
+			result = KErrNoMemory;
+		}
+
+	if (result == KErrNone)
+		{		
+		// Create the brush object
+		// This only need to be done the first time the context is activated
+		iBrush = vgCreatePaint();
+		if (iBrush != VG_INVALID_HANDLE)
+			vgSetPaint(iBrush, VG_FILL_PATH);
+		else
+			result = KErrNoMemory;
+		}
+	
+	if (result == KErrNone)
+		{
+		// Create the brush object for Clear operations.
+		// This only need to be done the first time the context is activated
+		iClearBrush = vgCreatePaint();
+		if (iClearBrush == VG_INVALID_HANDLE)
+			{
+			result = KErrNoMemory;
+			}
+		}
+	
+	if (result == KErrNone)
+		{
+		iTextBrush = vgCreatePaint();
+		if (iTextBrush == VG_INVALID_HANDLE)
+			{
+			result = KErrNoMemory;
+			}
+		}
+	
+	if (result == KErrNone)
+		{
+		result = iDriver.PreAllocateFontGlyphImages();
+		}
+
+	if (result == KErrNone)
+		{
+		SetVgState();
+		}
+
+	return result;
+	}
+
+/**
+@see MDirectGdiEngine::Deactivate()
+@see Activate()
+ */
+void CVgEngine::Deactivate()
+	{
+	if (iPen != VG_INVALID_HANDLE)
+		{
+		vgDestroyPaint(iPen);
+		}
+	if (iBrush != VG_INVALID_HANDLE)
+		{
+		vgDestroyPaint(iBrush);		
+		}
+	if (iClearBrush != VG_INVALID_HANDLE)
+		{
+		vgDestroyPaint(iClearBrush);		
+		}
+	if (iTextBrush != VG_INVALID_HANDLE)
+		{
+		vgDestroyPaint(iTextBrush);		
+		}
+	if (iVgPath != VG_INVALID_HANDLE)
+		{
+		vgDestroyPath(iVgPath);
+		}
+	iPen = VG_INVALID_HANDLE;
+	iBrush = VG_INVALID_HANDLE;
+	iClearBrush = VG_INVALID_HANDLE;
+	iVgPath = VG_INVALID_HANDLE;
+	iTextBrush = VG_INVALID_HANDLE;
+	
+	if (iRenderingTarget)
+		{
+		// Deactivating the render target could potentially unbind the current EGL context
+		// which would make the above vgDestroy() calls do nothing, therefore call Deactivate() last.
+		iDriver.Deactivate(iRenderingTarget);
+		}
+	}
+
+/**
+Checks whether the engine and target are current. If current, then nothing is done, else all the OpenVG settings 
+and EGL context are reapplied. This function is called in every drawing function to ensure that the engine and 
+target are current.
+
+If this function returns EFalse, it means any subsequent setting of OpenVG state may be invalid 
+and should be avoided as it is setting a null EGL context.
+
+@pre	None.
+@post	Applies the current state to OpenVG and is made the active EGL context, if the engine or target is 
+        not current.
+@return ETrue if as a result of calling this function, the underlying OpenVG context is now current. This
+        effectively means whether we have a target or not. EFalse is returned otherwise.
+*/
+TBool CVgEngine::MakeEngineCurrent()
+	{
+	TBool vgCurrent = iRenderingTarget!=NULL;
+	if(!iDriver.IsCurrentEngine(this) || !iDriver.IsCurrentTarget(iRenderingTarget))
+		{
+		iDriver.SetCurrentEngine(this);
+		iDriver.SetCurrentTarget(iRenderingTarget);
+		// Must reactivate the target (i.e. make it current to EGL) before resetting the OpenVG parameters.
+		if (iRenderingTarget)
+			{
+			iDriver.Reactivate(iRenderingTarget);
+			SetVgState();
+			}
+		else
+			vgCurrent = EFalse;
+		}
+	
+	return vgCurrent;
+	}
+
+/**
+@see MDirectGdiEngine::SetOrigin()
+ */
+void CVgEngine::SetOrigin(const TPoint& aOrigin)
+	{
+	iOrigin = aOrigin + iDrawOrigin;
+	
+	if (!MakeEngineCurrent())
+		return;
+
+	ResetVgMatrix();
+	}
+
+/** 
+@see MDrawDeviceOrigin::Set()
+*/
+TInt CVgEngine::Set(const TPoint& aDrawOrigin)
+	{
+	TPoint moveOrigin=aDrawOrigin;
+ 	moveOrigin-=iDrawOrigin;
+ 	iOrigin+=moveOrigin;
+ 	
+ 	//offset clipping region
+ 	TInt result = KErrNone;
+ 	RRegion clippingRegion;
+ 	clippingRegion.Copy(iRegionManager.ClippingRegion());
+ 	if(!clippingRegion.CheckError())
+ 		{
+ 		clippingRegion.Offset(moveOrigin);
+ 		result = iRegionManager.SetClippingRegion(clippingRegion);
+ 		}
+ 	else
+ 		{
+ 		result = KErrNoMemory;
+ 		}
+ 	
+ 	if(result != KErrNone)
+ 		{
+ 		iDriver.SetError(result);
+ 		}
+ 	
+ 	clippingRegion.Close();
+ 	
+ 	iDrawOrigin = aDrawOrigin;
+ 	return result;
+ 	}
+ 
+/** 
+@see MDrawDeviceOrigin::Get()
+*/
+void CVgEngine::Get(TPoint& aDrawOrigin)
+ 	{
+ 	aDrawOrigin=iDrawOrigin;
+   	}
+
+/**
+@see MDirectGdiEngine::SetClippingRegion(const TRegion&)
+*/
+void CVgEngine::SetClippingRegion(const TRegion& aRegion)
+	{
+	TInt result = KErrNone;
+	TRect boundingRect=iTargetRegion.BoundingRect();
+	boundingRect.iTl-=iDrawOrigin;
+	boundingRect.iBr-=iDrawOrigin;
+	if (!aRegion.IsContainedBy(boundingRect))
+		{
+		result = KErrArgument;
+		}
+	else
+		{
+		RRegion clippingRegion;
+		clippingRegion.Copy(aRegion);
+		if(!clippingRegion.CheckError())
+			{
+			clippingRegion.Offset(iDrawOrigin);
+			result = iRegionManager.SetClippingRegion (clippingRegion);
+			}
+		else
+			{
+			result = KErrNoMemory;
+			}
+		clippingRegion.Close();
+		}
+	
+	if (result != KErrNone)
+		{
+		iDriver.SetError(result);
+		}
+	}
+
+/**
+@see MDirectGdiEngine::ResetClippingRegion()
+*/
+void CVgEngine::ResetClippingRegion()
+	{
+	iRegionManager.Reset();
+	
+	if (!MakeEngineCurrent())
+		return;
+		
+	vgSeti(VG_SCISSORING, VG_FALSE);
+	}
+
+/**
+@see MDirectGdiEngine::SetDrawMode()
+
+The generic layer has already checked whether the draw mode is already aMode.
+Draw mode is referred to as "blend" mode in OpenVG.
+Note that only EDrawModePEN and EDrawModeWriteAlpha style blending are supported by OpenVG.
+The default OpenVG blend mode is VG_BLEND_SRC_OVER.
+ */
+void CVgEngine::SetDrawMode(DirectGdi::TDrawMode aMode)
+	{
+	iDrawMode = aMode;
+	
+	if (!MakeEngineCurrent())
+		return;
+
+	// Invalid modes are filtered out in the generic layer.
+	if (aMode == DirectGdi::EDrawModePEN)
+		{
+		// Blend the destination with the source using the source alpha for blending if 
+		// alpha is available.		
+		vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
+		}
+	else // DirectGdi::EDrawModeWriteAlpha
+		{
+		// Destination colors and alpha are overwritten with source colors and alpha.						
+		vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);											
+		}
+	}
+
+/**
+@see MDirectGdiEngine::SetPenColor()
+*/
+void CVgEngine::SetPenColor(const TRgb& aColor)
+	{
+	iPenColor = aColor;
+	
+	if (!MakeEngineCurrent())
+		return;
+
+	// Make sure our pen is the current selected pen for stroking before we set the color	
+	vgSetPaint(iPen, VG_STROKE_PATH);	
+	
+	// Set the color
+	vgSetParameteri(iPen, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+	SetVgPaintColor(iPen, iPenColor);	
+	SetVgPaintColor(iTextBrush, iPenColor);
+	}
+
+/**
+Set the current pen style for drawing lines. This corresponds to setting the "stroke dash" pattern in OpenVG.
+
+@see MDirectGdiEngine::SetPenStyle()
+ */
+void CVgEngine::SetPenStyle(DirectGdi::TPenStyle aStyle)
+	{
+	iPenStyle = aStyle;
+	
+	if (!MakeEngineCurrent())
+		return;
+	
+	iPaintMode = iPaintMode | VG_STROKE_PATH;		
+	
+	switch (aStyle)
+		{
+		case DirectGdi::ENullPen:
+			{
+			iPaintMode = iPaintMode & (~VG_STROKE_PATH); // Unset stroke bit
+			vgSetfv(VG_STROKE_DASH_PATTERN, 0, NULL);
+			vgSetf(VG_STROKE_DASH_PHASE, 0.f);
+			break;
+			}
+			
+		case DirectGdi::ESolidPen:
+			{
+			vgSetfv(VG_STROKE_DASH_PATTERN, 0, NULL);	
+			vgSetf(VG_STROKE_DASH_PHASE, 0.f);
+			break;
+			}
+			
+		case DirectGdi::EDottedPen:
+			{
+			VGfloat offset = (iPenSize.iWidth > 1) ? 2.f : 0.f;			
+			VGfloat dashPattern[2] = {(1*iPenSize.iWidth)-offset, (3*iPenSize.iWidth)+offset};
+			vgSetfv(VG_STROKE_DASH_PATTERN, 2, dashPattern);
+			vgSetf(VG_STROKE_DASH_PHASE, 1.f);
+			break;
+			}
+			
+		case DirectGdi::EDashedPen:
+			{
+			VGfloat offset = (iPenSize.iWidth > 1) ? 2.f : 0.f;			
+			VGfloat dashPattern[2] = {(3*iPenSize.iWidth)-offset, (3*iPenSize.iWidth)+offset};
+			vgSetfv(VG_STROKE_DASH_PATTERN, 2, dashPattern);
+			vgSetf(VG_STROKE_DASH_PHASE, (iPenSize.iWidth != 1) ? 1.f : 0.f);
+			break;
+			}
+			
+		case DirectGdi::EDotDashPen:
+			{
+			VGfloat offset = (iPenSize.iWidth > 1) ? 2.f : 0.f;			
+			VGfloat dashPattern[4] = {(1*iPenSize.iWidth)-offset, (3*iPenSize.iWidth)+offset, (3*iPenSize.iWidth)-offset, (3*iPenSize.iWidth)+offset};
+			vgSetfv(VG_STROKE_DASH_PATTERN, 4, dashPattern);
+			vgSetf(VG_STROKE_DASH_PHASE, 1.f);
+			break;
+			}
+			
+		case DirectGdi::EDotDotDashPen:
+			{
+			VGfloat offset = (iPenSize.iWidth > 1) ? 2.f : 0.f;			
+			VGfloat dashPattern[6] = {(1*iPenSize.iWidth)-offset, (3*iPenSize.iWidth)+offset, (1*iPenSize.iWidth)-offset, (3*iPenSize.iWidth)+offset, (3*iPenSize.iWidth)-offset, (3*iPenSize.iWidth)+offset};
+			vgSetfv(VG_STROKE_DASH_PATTERN, 6, dashPattern);
+			vgSetf(VG_STROKE_DASH_PHASE, (iPenSize.iWidth != 1) ? 1.f : 0.f);
+			break;			
+			}
+			
+		default:
+			{
+			// Copy BitGdi behaviour here and draw a solid line for any unknown pen style
+			vgSetfv(VG_STROKE_DASH_PATTERN, 0, NULL);
+			vgSetf(VG_STROKE_DASH_PHASE, 0.f);
+			break;		
+			}
+		}
+	}
+
+
+/**
+@see MDirectGdiEngine::SetPenSize()
+ */
+void CVgEngine::SetPenSize(const TSize& aSize)
+	{
+	iPenSize = aSize;
+	
+	if (!MakeEngineCurrent())
+		return;
+
+	// VG_STROKE_LINE_WIDTH expects a float	
+	// Note that we set the pen size using just the width in the assumption that the pen width
+	// and height are normally the same. For the special cases where the pen width and height
+	// are different, the pen size is set to (1,1) then scaled to give the effect of a pen with 
+	// different width and height. This is done for all functions in this file that draws shapes,  
+	// see Plot(), DrawLine(), DrawArc(), DrawRect() etc.
+	vgSetf(VG_STROKE_LINE_WIDTH, aSize.iWidth);	
+		
+	// Re-set the pen style as the pen size has changed, SetPenStyle() uses the pen size to set 
+	// the dotted line styles.
+	SetPenStyle(iPenStyle);
+	}
+
+/**
+@see MDirectGdiEngine::SetTextShadowColor()
+*/
+void CVgEngine::SetTextShadowColor(const TRgb& aColor)
+	{
+	iTextShadowColor = aColor; //just cache this color
+	}
+
+
+/**
+@see MDirectGdiEngine::SetBrushColor()
+*/
+void CVgEngine::SetBrushColor(const TRgb& aColor)
+	{
+	iBrushColor = aColor;
+	
+	if (!MakeEngineCurrent())
+		return;
+	
+	// Convert the color components as that they are between 0.0f and 1.0f
+	VGfloat color[4];	
+	color[0] = aColor.Red() * KColorConversion;
+	color[1] = aColor.Green() * KColorConversion;
+	color[2] = aColor.Blue() * KColorConversion;
+	color[3] = aColor.Alpha() * KColorConversion;
+
+	// Make sure our brush is the current selected brush for filling before we set the color
+	if (iBrushStyle != DirectGdi::ENullBrush)
+		vgSetPaint(iBrush, VG_FILL_PATH);	
+	
+	vgSetParameteri(iBrush, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+	vgSetParameterfv(iBrush, VG_PAINT_COLOR, 4, color);
+	
+	// Set the clear color and the tile fill color as well as these should both
+	// be the same as the brush color
+	vgSetParameterfv(iClearBrush, VG_PAINT_COLOR, 4, color);
+	vgSetfv(VG_CLEAR_COLOR, 4, color);
+	vgSetfv(VG_TILE_FILL_COLOR, 4, color);
+	
+	// If using a patterned brush, need to reconstruct it as the colours may be out of sync.
+	if ((iBrushStyle != DirectGdi::ENullBrush) && (iBrushStyle != DirectGdi::ESolidBrush))
+		{
+		SetBrushStyle(iBrushStyle);
+		}	
+	}
+
+
+/**
+The DirectGDI brush styles do not map directly to OpenVG, so brushes for styles > DirectGdi::EPatternedBrush
+are created as bitmaps before being set.
+
+@see MDirectGdiEngine::SetBrushColor()
+@see CreateStandardBrush()
+*/
+void CVgEngine::SetBrushStyle(DirectGdi::TBrushStyle aStyle) 
+	{	
+	iBrushStyle = aStyle;
+	
+	if (!MakeEngineCurrent())
+		return;
+	
+	TInt standardBrushErr = KErrNone;
+	const TInt standardBrushSize = 3;
+	const TInt standardBrushArea = standardBrushSize*standardBrushSize;
+	const TInt diamondCrossHatchBrushSize = 4;
+	const TInt diamondCrossHatchBrushArea = diamondCrossHatchBrushSize*diamondCrossHatchBrushSize;
+	
+	// Select the brush for drawing any style that is not ENullBrush
+	iPaintMode = iPaintMode | VG_FILL_PATH;
+	if (aStyle != DirectGdi::ENullBrush)
+		vgSetPaint(iBrush, VG_FILL_PATH);
+
+	// Paint using a pattern for all styles that are not ENullBrush or ESolidBrush
+	if ((aStyle != DirectGdi::ENullBrush) && (aStyle != DirectGdi::ESolidBrush))
+		{		
+		vgSetParameteri(iBrush, VG_PAINT_TYPE, VG_PAINT_TYPE_PATTERN);
+		vgSetParameteri(iBrush, VG_PAINT_PATTERN_TILING_MODE, VG_TILE_REPEAT);
+		}	
+
+	switch (aStyle)
+		{
+		case DirectGdi::ENullBrush:					
+			iPaintMode = iPaintMode & (~VG_FILL_PATH);
+			
+			// Clear the current brush so that no brush color is drawn
+			vgSetPaint(VG_INVALID_HANDLE, VG_FILL_PATH);
+			break;			
+
+		case DirectGdi::ESolidBrush:			
+			// Paint using a solid color
+			vgSetParameteri(iBrush, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+			break;			
+
+		case DirectGdi::EPatternedBrush:						
+			// Make sure the user has set a patterned brush for use
+			GRAPHICS_ASSERT_ALWAYS(iBrushPatternUser != VG_INVALID_HANDLE, EDirectGdiPanicPatternedBrushNotSet);						
+			
+			if (NonZeroBrushPatternOrigin())
+				{
+				// The brush origin is non-zero, update the non-zero origin brush 
+				// with the user brush and use that instead of the user brush
+				CopyCurrentBrushPatternForNonZeroOrigin();										
+				}
+			else
+				{
+				// Set the brush to fill with the user selected bitmap pattern
+				vgPaintPattern(iBrush, iBrushPatternUser);
+				}
+			break;			
+
+		case DirectGdi::EVerticalHatchBrush:
+			{
+			// The brush fills with vertical hatching  lines going from top to bottom
+			TSize size(standardBrushSize, standardBrushSize);
+			VGbyte brushPattern[standardBrushArea] = {0,0,1, 0,0,1, 0,0,1};
+			standardBrushErr = CreateStandardBrush(size, brushPattern);
+			break;
+			}
+		
+		case DirectGdi::EForwardDiagonalHatchBrush:
+			{
+			// The brush fills with diagonal hatching lines going from bottom left to top right
+			TSize size(standardBrushSize, standardBrushSize);
+			VGbyte brushPattern[standardBrushArea] = {1,0,0, 0,0,1, 0,1,0};
+			standardBrushErr = CreateStandardBrush(size, brushPattern);
+			break;
+			}
+		
+		case DirectGdi::EHorizontalHatchBrush:
+			{
+			// The brush fills with horizontal hatching lines going from left to right
+			TSize size(standardBrushSize, standardBrushSize);
+			VGbyte brushPattern[standardBrushArea] = {0,0,0, 0,0,0, 1,1,1};
+			standardBrushErr = CreateStandardBrush(size, brushPattern);
+			break;
+			}
+		
+		case DirectGdi::ERearwardDiagonalHatchBrush:
+			{
+			// The brush fills with rearward diagonal hatching lines going from top left to bottom right
+			TSize size(standardBrushSize, standardBrushSize);
+			VGbyte brushPattern[standardBrushArea] = {1,0,0, 0,1,0, 0,0,1};
+			standardBrushErr = CreateStandardBrush(size, brushPattern);
+			break;
+			}
+		
+		case DirectGdi::ESquareCrossHatchBrush:
+			{
+			// The brush fills with horizontal and vertical hatching lines going from left to right 
+			// plus lines going from top to bottom  giving the effect of a grid of small squares
+			TSize size(standardBrushSize, standardBrushSize);
+			VGbyte brushPattern[standardBrushArea] = {0,0,1, 0,0,1, 1,1,1};
+			standardBrushErr = CreateStandardBrush(size, brushPattern);
+			break;
+			}
+		
+		case DirectGdi::EDiamondCrossHatchBrush:
+			{
+			// The brush fills with forward diagonal and rearward diagonal hatching lines going from  
+			// bottom left to top right plus lines going from top left to bottom right giving the effect  
+			// of a grid of small diamonds
+			// The brush fills with diagonal hatching lines going from bottom left to top right
+			TSize size(diamondCrossHatchBrushSize, diamondCrossHatchBrushSize);
+			VGbyte brushPattern[diamondCrossHatchBrushArea] = {0,0,1,0, 0,1,0,1, 1,0,0,0, 0,1,0,1};
+			standardBrushErr = CreateStandardBrush(size, brushPattern);
+			break;	
+			}		
+		}
+	
+	// Select the standard brush for all styles > EPatternedBrush
+	if (aStyle > DirectGdi::EPatternedBrush)
+		{
+		if (standardBrushErr == KErrNone)
+			{
+			if (NonZeroBrushPatternOrigin())
+				{
+				// The brush origin is non-zero, update the non-zero origin brush 
+				// with the standard brush and use that instead of the standard brush
+				CopyCurrentBrushPatternForNonZeroOrigin();
+				}
+			else
+				{
+				// Use the standard brush region
+				vgPaintPattern(iBrush, iBrushPatternStandardRegion);
+				}
+			}
+		else
+			{
+			iDriver.SetError(standardBrushErr);
+			}
+		}
+	else
+		{
+		vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
+		}
+	}
+
+/**
+@see MDirectGdiEngine::SetBrushOrigin()
+ */
+void CVgEngine::SetBrushOrigin(const TPoint& aOrigin) 
+	{
+	iBrushOrigin = aOrigin;
+	if (NonZeroBrushPatternOrigin())
+		{
+		// Copy the current brush pattern into iBrushPatternNonZeroOrigin, but shift it to
+		// take into account the current non-zero brush origin.
+		CopyCurrentBrushPatternForNonZeroOrigin();		
+		}
+	}
+
+
+/**
+@see MDirectGdiEngine::SetBrushPattern()
+ */
+TInt CVgEngine::SetBrushPattern(const CFbsBitmap& aPattern) 
+	{
+	if (aPattern.ExtendedBitmapType() != KNullUid)
+		{
+		return KErrNotSupported; // Not supported for extended bitmaps
+		}
+	
+	// Destroy any previously set brush pattern
+	MakeEngineCurrent();
+	ResetBrushPattern();	
+	iBrushPatternUser = CreateSourceVGImage(aPattern);
+	if (iBrushPatternUser == VG_INVALID_HANDLE)
+		{
+		return KErrNoMemory;
+		}
+
+	iBrushPatternUserSize = aPattern.SizeInPixels();
+	iBrushPatternUserBitmapHandle = aPattern.Handle();
+	return KErrNone;
+	}
+
+
+/**
+@see MDirectGdiEngine::ResetBrushPattern()
+ */
+void CVgEngine::ResetBrushPattern() 
+	{
+	MakeEngineCurrent();
+	if (iBrushPatternUser != VG_INVALID_HANDLE)
+		{
+		vgDestroyImage(iBrushPatternUser);
+		iBrushPatternUser = VG_INVALID_HANDLE;
+		iBrushPatternUserBitmapHandle = KNullHandle;
+		iBrushPatternUserSize = TSize(0,0);
+		}	
+	}
+
+/**
+@see MDirectGdiEngine::SetFont()
+*/
+void CVgEngine::SetFont(TUint32 aFontId) 
+	{
+	iFontId = aFontId;
+	}
+
+
+/**
+@see MDirectGdiEngine::ResetFont()
+ */
+void CVgEngine::ResetFont() 
+	{
+	iFontId = 0;
+	}
+
+/**
+Reset all the VgEngine-specific settings. Generic settings such as paint colour and pen colour
+are set by calls from the CDirectGdiContext.
+	
+@see MDirectGdiEngine::Reset()
+
+@post All VgEngine-specific settings have been reset to their default values.
+ */
+void CVgEngine::Reset() 
+	{
+	if (!MakeEngineCurrent())
+		return;
+
+	ResetVgMatrix();
+	}
+
+
+
+/**
+@see MDirectGdiEngine::Clear(const TRect&)
+
+@panic DGDIAdapter 62, if the brush for clearing is not valid (debug-only).
+*/
+void CVgEngine::Clear(const TRect& aRect) 
+	{
+	MakeEngineCurrent();
+
+	if (255 == iBrushColor.Alpha())
+		{
+		const TPoint rectOrigin = ConvertToVgCoords(aRect);
+		for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+			vgClear(rectOrigin.iX, rectOrigin.iY, aRect.Width(), aRect.Height());
+		}
+	else
+		{
+		// If blending is enabled, we cannot use vgClear as it ignores the current blendmode and performs a WriteAlpha.
+		// Therefore a clear is done by a filled rectangle.
+		
+		// The Clear brush should always be a solid brush.
+		GRAPHICS_ASSERT_DEBUG(vgGetParameteri(iClearBrush, VG_PAINT_TYPE) == VG_PAINT_TYPE_COLOR, EDirectGdiPanicClearBrushInvalid);
+				
+		if (PreparePath(iVgPath, 5))
+			{
+			// Before any vgu command, call SetError() as this stores the current OpenVG error state (if any) 
+			// on the driver. Some implementations of vgu clears error state so we'd lose error codes otherwise.
+			iDriver.SetError(KErrNone);
+			
+			VGUErrorCode err = vguRect(iVgPath, aRect.iTl.iX, aRect.iTl.iY, aRect.Width(), aRect.Height());
+			if (err == VGU_NO_ERROR)
+				{
+				// Temporarily set the brush to the clear brush and fill the path.
+				vgSetPaint(iClearBrush, VG_FILL_PATH);
+				for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+					vgDrawPath(iVgPath, VG_FILL_PATH);
+				vgSetPaint(iBrush, VG_FILL_PATH);	
+				}
+			else
+				{
+				SetVguError(err);
+				}
+			}
+		}
+	}
+
+/**
+@see MDirectGdiEngine::Clear()
+ */
+void CVgEngine::Clear() 
+	{
+	Clear(TRect(iSize));
+	}
+
+/**
+@see MDirectGdiEngine::MoveTo()
+ */
+void CVgEngine::MoveTo(const TPoint& aPoint) 
+	{
+	iLinePos = aPoint;
+	}
+
+/**
+@see MDirectGdiEngine::MoveBy()
+ */
+void CVgEngine::MoveBy(const TPoint& aVector) 
+	{
+	iLinePos += aVector;
+	}
+
+/**
+@see MDirectGdiEngine::Plot()
+ */
+void CVgEngine::Plot(const TPoint& aPoint) 
+	{
+	MakeEngineCurrent();
+	GRAPHICS_ASSERT_DEBUG(vgGeti(VG_STROKE_CAP_STYLE) == VG_CAP_ROUND,  EDirectGdiPanicPenEndCapStyleNotRound);
+
+	
+	// If the pen width and height are equal just plot as normal. 
+	if (iPenSize.iWidth == iPenSize.iHeight)
+		{
+		if (PreparePath(iVgPath, 2))
+			{
+			// A point is plotted by drawing a line with start and end points the same.
+			AppendPathCommand(VG_MOVE_TO_ABS, aPoint.iX + 0.5f, aPoint.iY + 0.5f);
+			AppendPathCommand(VG_HLINE_TO_REL, 0.f);
+			FinishPath(iVgPath);
+			
+			for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+				vgDrawPath(iVgPath, iPaintMode&VG_STROKE_PATH);
+			}
+		}
+	else if ((iPenSize.iWidth != 0) && (iPenSize.iHeight != 0))
+		{
+		// Setting a pen with different width and height is not available on OpenVG, so we need to scale 
+		// the coordinates we are drawing and apply a scaling matrix that scales by the width and height 
+		// of the pen to get the effect of a pen width different width and height.
+		if (PreparePath(iVgPath, 2))
+			{
+			TSize penSize = iPenSize;
+			SetPenSize(TSize(1, 1));
+			vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+			vgScale(penSize.iWidth, penSize.iHeight);
+			
+			// A point is plotted by drawing a line with start and end points the same.
+			AppendPathCommand(VG_MOVE_TO_ABS, (aPoint.iX + 0.5f)/(float)penSize.iWidth, (aPoint.iY + 0.5f)/(float)penSize.iHeight);
+			AppendPathCommand(VG_HLINE_TO_REL, 0.f);
+			FinishPath(iVgPath);
+			
+			vgDrawPath(iVgPath, iPaintMode&VG_STROKE_PATH);
+			
+			ResetVgMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
+			SetPenSize(penSize);
+			}								
+		}	
+	}
+
+/**
+@see MDirectGdiEngine::DrawLine()
+ */
+void CVgEngine::DrawLine(const TPoint& aStart, const TPoint& aEnd)
+	{
+	MakeEngineCurrent();
+	GRAPHICS_ASSERT_DEBUG(vgGeti(VG_STROKE_CAP_STYLE) == VG_CAP_ROUND, EDirectGdiPanicPenEndCapStyleNotRound);
+	
+    if (iPaintMode == 0)
+		{
+		return;
+		}    
+	
+	if (PreparePath(iVgPath, 2))
+		{
+		// If the pen width and height are the same then draw as normal
+		if (iPenSize.iWidth == iPenSize.iHeight)
+			{
+			// 0.5 is appended to all OpenVG drawing co-ordinates as when specifying them, the spec says
+			// co-ordinates are relative to pixel boundaries, not pixel centres, so 0,0 is the top left of the
+			// top pixel. We need to add 0.5 to specify the centre of pixels.
+			
+			AppendPathCommand(VG_MOVE_TO_ABS, aStart.iX + 0.5f, aStart.iY + 0.5f);		
+			if (aStart.iX == aEnd.iX)
+				{
+				AppendPathCommand(VG_VLINE_TO_ABS, aEnd.iY + 0.5f);			
+				}
+			else if (aStart.iY == aEnd.iY)
+				{
+				AppendPathCommand(VG_HLINE_TO_ABS, aEnd.iX + 0.5f);			
+				}
+			else
+				{
+				AppendPathCommand(VG_LINE_TO_ABS, aEnd.iX + 0.5f, aEnd.iY + 0.5f);
+				}		
+			FinishPath(iVgPath);
+			for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+				vgDrawPath(iVgPath, iPaintMode);			
+			}
+		else if ((iPenSize.iWidth != 0) && (iPenSize.iHeight != 0))
+			{
+			// Setting a pen with different width and height is not available on OpenVG, so we need to scale 
+			// the coordinates we are drawing and apply a scaling matrix that scales by the width and height 
+			// of the pen to get the effect of a pen width different width and height.
+			TSize penSize = iPenSize;
+			SetPenSize(TSize(1, 1));
+			vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+			vgScale(penSize.iWidth, penSize.iHeight);
+					
+			VGfloat scaleX = 1.0f/(float)penSize.iWidth;
+			VGfloat scaleY = 1.0f/(float)penSize.iHeight;
+			AppendPathCommand(VG_MOVE_TO_ABS, (aStart.iX + 0.5f)*scaleX, (aStart.iY + 0.5f)*scaleY);		
+			if (aStart.iX == aEnd.iX)
+				{
+				AppendPathCommand(VG_VLINE_TO_ABS, (aEnd.iY + 0.5f)*scaleY);			
+				}
+			else if (aStart.iY == aEnd.iY)
+				{
+				AppendPathCommand(VG_HLINE_TO_ABS, (aEnd.iX + 0.5f)*scaleX);			
+				}
+			else
+				{
+				AppendPathCommand(VG_LINE_TO_ABS, (aEnd.iX + 0.5f)*scaleX, (aEnd.iY + 0.5f)*scaleY);
+				}		
+			FinishPath(iVgPath);				
+			vgDrawPath(iVgPath, iPaintMode);
+			
+			ResetVgMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
+			SetPenSize(penSize);
+			}			
+		}	
+
+	iLinePos = aEnd;
+	}
+
+/**
+@see MDirectGdiEngine::DrawLineTo()
+ */
+void CVgEngine::DrawLineTo(const TPoint& aPoint)
+	{
+	DrawLine(iLinePos, aPoint);
+	}
+
+/**
+@see MDirectGdiEngine::DrawLineBy()
+ */
+void CVgEngine::DrawLineBy(const TPoint& aVector)
+	{
+	DrawLine(iLinePos, iLinePos + aVector);
+	}
+
+/**
+@see MDirectGdiEngine::DrawRect()
+ */
+void CVgEngine::DrawRect(const TRect& aRect)
+	{
+	MakeEngineCurrent();
+	
+	// Only draw if we are not painting with a NULL pen and a NULL brush
+	if (iPaintMode == 0)
+		return;
+	
+	// If the pen size is larger then 1, make sure we are using the ESolidPen
+	// pen style (to match BitGdi behaviour)
+	DirectGdi::TPenStyle savedPenStyle = iPenStyle;
+	if (((iPenSize.iWidth > 1) || (iPenSize.iHeight > 1)) && (iPenStyle > DirectGdi::ESolidPen))
+		SetPenStyle(DirectGdi::ESolidPen);
+	
+	// Create a copy of the rect. If the pen style is not null, we have to shrink the 
+	// width and height of the rect by one pixel at the bottom left corner for conformance.	
+	TRect copyRect(aRect.iTl.iX, aRect.iTl.iY, aRect.iBr.iX, aRect.iBr.iY-1);
+	if (iPenStyle != DirectGdi::ENullPen)
+		{
+		--copyRect.iBr.iX;
+		}
+	else
+		{
+		--copyRect.iTl.iY;
+		}
+
+	const TBool symmetricalPenSize = iPenSize.iWidth == iPenSize.iHeight;
+	
+	// If the pen is so thick it covers the entire area of the rect, don't do the fill, as per BitGdi.
+	const TBool penThickerThanRect = (iPenSize.iWidth >= copyRect.Width()) || (iPenSize.iHeight >= copyRect.Height());
+	
+	// If the pen width and height are the same then draw as normal. If they are different but we should be filling
+	// this shape we need to draw the filled area only as normal (not the outline). The outline of the shape is drawn 
+	// in the block of code below to allow the effect of a different width and height pen to be applied.
+	if (!penThickerThanRect || (iPenStyle == DirectGdi::ENullPen))
+		{
+		if (symmetricalPenSize || (iPaintMode & VG_FILL_PATH))
+			{
+			if (PreparePath(iVgPath, 5))
+				{
+				vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_MITER);
+				AppendPathCommand(VG_MOVE_TO_ABS, copyRect.iTl.iX + 0.5f, copyRect.iTl.iY + 0.5f);
+				AppendPathCommand(VG_HLINE_TO_ABS, copyRect.iBr.iX + 0.5f);
+				AppendPathCommand(VG_VLINE_TO_ABS, copyRect.iBr.iY + 0.5f);
+				AppendPathCommand(VG_HLINE_TO_ABS, copyRect.iTl.iX + 0.5f);
+				AppendPathCommand(VG_CLOSE_PATH);
+				FinishPath(iVgPath);
+			
+				for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+					vgDrawPath(iVgPath, symmetricalPenSize ? iPaintMode : VG_FILL_PATH);
+				vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
+				}
+			}
+		}
+	if((penThickerThanRect && (iPenStyle != DirectGdi::ENullPen)) ||  //we shouldn't draw if pen style is null
+		(!symmetricalPenSize &&	(iPaintMode & VG_STROKE_PATH) && (iPenSize.iWidth != 0) && (iPenSize.iHeight != 0)))
+		{
+		// Setting a pen with different width and height is not available on OpenVG, so we need to scale 
+		// the coordinates we are drawing and apply a scaling matrix that scales by the width and height 
+		// of the pen to get the effect of a pen width different width and height.
+		TSize penSize = iPenSize;
+		SetPenSize(TSize(1, 1));
+		vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+		vgScale(penSize.iWidth, penSize.iHeight);
+			
+		if (PreparePath(iVgPath, 5))
+			{
+			vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_MITER);
+			VGfloat scaleX = 1.0f/(float)penSize.iWidth;
+			VGfloat scaleY = 1.0f/(float)penSize.iHeight;
+			AppendPathCommand(VG_MOVE_TO_ABS, (copyRect.iTl.iX + 0.5f)*scaleX, (copyRect.iTl.iY + 0.5f)*scaleY);
+			AppendPathCommand(VG_HLINE_TO_ABS, (copyRect.iBr.iX + 0.5f)*scaleX);
+			AppendPathCommand(VG_VLINE_TO_ABS, (copyRect.iBr.iY + 0.5f)*scaleY);
+			AppendPathCommand(VG_HLINE_TO_ABS, (copyRect.iTl.iX + 0.5f)*scaleX);
+			AppendPathCommand(VG_CLOSE_PATH);
+			FinishPath(iVgPath);
+			for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+				vgDrawPath(iVgPath, VG_STROKE_PATH);
+			vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
+			}
+		
+		ResetVgMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
+		SetPenSize(penSize);
+		}
+
+	// Reset the pen style if we changed it above
+	if (savedPenStyle != iPenStyle)
+		SetPenStyle(savedPenStyle);
+	}
+
+/**
+@see MDirectGdiEngine::DrawRoundRect()
+ */
+void CVgEngine::DrawRoundRect(const TRect& aRect, const TSize& aCornerSize) 
+	{
+	MakeEngineCurrent();
+	
+	// Only draw if we are not painting with a NULL pen and a NULL brush
+	if (iPaintMode == 0)		
+		return;
+	
+	// Create a copy of the rect. If the pen style is not null, we have to shrink the 
+	// width and height of the rect by one pixel at the bottom left corner for conformance.	
+	TRect copyRect(aRect.iTl.iX, aRect.iTl.iY, aRect.iBr.iX, aRect.iBr.iY-1);
+	if (iPenStyle != DirectGdi::ENullPen)
+		{
+		--copyRect.iBr.iX;
+		}
+	//If the penstyle is null and brush style is not null, then reduce the width and height by
+	//two pixels for conformation.
+	else if(iBrushStyle != DirectGdi::ENullBrush)
+		{
+		----copyRect.iBr.iX;		
+		--copyRect.iBr.iY;
+		}
+	else if(iPenStyle == DirectGdi::ENullPen)
+		{
+		--copyRect.iTl.iY;
+		}
+	
+	// check that the corner size is less than the rectangle size
+	if ((aRect.Width() > aCornerSize.iWidth) || (aRect.Height() > aCornerSize.iHeight))
+		{									
+		// Before any vgu command, call SetError() as this stores the current vg error state (if any) in the 
+		// driver. Some implementations of vgu clears error state so we'd lose error codes otherwise.
+		iDriver.SetError(KErrNone);
+		
+		// If the pen width and height are the same then draw as normal. If they are different but we should be filling
+		// this shape we need to draw the filled area only as normal (not the outline). The outline of the shape is drawn 
+		// in the block of code below to allow the effect of a different width and height pen to be applied.
+		if ((iPenSize.iWidth == iPenSize.iHeight) || (iPaintMode & VG_FILL_PATH))
+			{
+			if (PreparePath(iVgPath, 10))
+				{
+				VGUErrorCode err = vguRoundRect(iVgPath,
+											copyRect.iTl.iX + 0.5f, 
+											copyRect.iTl.iY + 0.5f,
+											copyRect.Width(), 
+											copyRect.Height(),
+											aCornerSize.iWidth * 2, 
+											aCornerSize.iHeight * 2);	
+				
+				if (err == VGU_NO_ERROR)
+					{
+					for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+						vgDrawPath(iVgPath, (iPenSize.iWidth == iPenSize.iHeight) ? iPaintMode : VG_FILL_PATH);	
+					}
+				else
+					{
+					SetVguError(err);
+					}
+				}
+			}
+		
+		if ((iPenSize.iWidth != iPenSize.iHeight)
+		&& (iPaintMode & VG_STROKE_PATH)		
+		&& (iPenSize.iWidth != 0) && (iPenSize.iHeight != 0))
+			{
+			// Setting a pen with different width and height is not available on OpenVG, so we need to scale 
+			// the coordinates we are drawing and apply a scaling matrix that scales by the width and height 
+			// of the pen to get the effect of a pen width different width and height.
+			TSize penSize = iPenSize;
+			SetPenSize(TSize(1, 1));
+			vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+			vgScale(penSize.iWidth, penSize.iHeight);
+			
+			if (PreparePath(iVgPath, 10))
+				{
+				VGfloat scaleX = 1.0f/(float)penSize.iWidth;
+				VGfloat scaleY = 1.0f/(float)penSize.iHeight;
+				VGUErrorCode err = vguRoundRect(iVgPath,
+							                (copyRect.iTl.iX + 0.5f) * scaleX, 
+							                (copyRect.iTl.iY + 0.5f) * scaleY,
+							                copyRect.Width() * scaleX, 
+							                copyRect.Height() * scaleY,
+							                (aCornerSize.iWidth * 2) * scaleX, 
+							                (aCornerSize.iHeight * 2) * scaleY);	
+				if (err == VGU_NO_ERROR)
+					{
+					vgDrawPath(iVgPath, VG_STROKE_PATH);		
+					}
+				else
+					{
+					SetVguError(err);
+					}
+				}
+			
+			ResetVgMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
+			SetPenSize(penSize);
+			}
+		}
+	else
+		{
+		// Draw an ellipse as the corner size is greater than or equal to the rectangle size
+		DrawEllipse(copyRect);
+		}
+	}
+
+/**
+@see MDirectGdiEngine::DrawPolyLine()
+
+@panic DGDIAdapter 27, if the passed point list has zero points (debug-only).
+ */
+void CVgEngine::DrawPolyLine(const TArray<TPoint>& aPointList)
+	{
+	DrawPolyLineNoEndPoint(aPointList);
+	
+	// Do a plot at the end point to improve the appearance. For larger pen-sizes, a plot
+	// improves the correlation with BitGDI polylines, giving a subtly more rounded finish.
+	if (DirectGdi::ESolidPen == iPenStyle)
+		{
+		Plot(iLinePos);
+		}
+	}
+
+/**
+@see MDirectGdiEngine::DrawPolyLineNoEndPoint()
+
+@panic DGDIAdapter 27, if the passed point list has zero points (debug-only).
+ */
+void CVgEngine::DrawPolyLineNoEndPoint(const TArray<TPoint>& aPointList)
+	{
+	MakeEngineCurrent();
+
+	GRAPHICS_ASSERT_DEBUG(aPointList.Count() > 0, EDirectGdiPanicInvalidPointArray);
+	
+	DoDrawPoly(aPointList, EFalse);
+	}
+
+/**
+@see MDirectGdiEngine::DrawPolygon()
+
+@panic DGDIAdapter 26, if the passed fill-rule is invalid (debug-only).
+ */
+void CVgEngine::DrawPolygon(const TArray<TPoint>& aPoints, DirectGdi::TFillRule aRule)
+	{
+	MakeEngineCurrent();
+	
+	GRAPHICS_ASSERT_DEBUG(aPoints.Count() > 0, EDirectGdiPanicInvalidPointArray);
+	
+	switch(aRule)
+	    {
+		case DirectGdi::EAlternate:
+			vgSeti(VG_FILL_RULE, VG_EVEN_ODD); 
+			break;
+		case DirectGdi::EWinding: 
+			vgSeti(VG_FILL_RULE, VG_NON_ZERO); 
+			break;
+		default: 
+			GRAPHICS_PANIC_DEBUG(EDirectGdiPanicInvalidFillRule);
+			return;
+	    };
+	
+	DoDrawPoly(aPoints, ETrue);
+	}
+
+/**
+Helper function to assist with drawing polygons with DrawPolygon()/DrawPolyLine(). It takes care of 
+drawing the array of points given to it. It sets the internal drawing poisition to the last TPoint
+in the array.
+
+@see	DrawPolyLine()
+@see 	DrawPolygon()
+
+@param	aPoints	Array of points specifying the vertices of the polygon. There must be at least one 
+		vertex.
+@param  aClosed	If ETrue, the start and end points are joined, and the polygon filled using current 
+        brush settings, otherwise just a polyline is drawn.
+*/
+void CVgEngine::DoDrawPoly(const TArray<TPoint>& aPoints, TBool aClosed)
+	{
+	GRAPHICS_ASSERT_DEBUG(aPoints.Count() > 0, EDirectGdiPanicInvalidPointArray);	
+	const TInt numPoints = aPoints.Count();	
+	
+	// Set drawing position to last point in the array (regardless of whether the poly is open/closed)
+	iLinePos = aPoints[numPoints - 1];
+	
+	// Set the paint mode depending on whether we are drawing a line (not closed) or a poly (closed)
+	VGbitfield paintMode = iPaintMode;
+	if (!aClosed)
+		{
+		paintMode &= ~VG_FILL_PATH;
+		}
+	
+	if (!paintMode)
+		{
+		return;
+		}
+
+	// If the pen width and height are the same then draw as normal. If they are different but we should be filling
+	// this shape we need to draw the filled area only as normal (not the outline). The outline of the shape is drawn 
+	// in the block of code below to allow the effect of a different width and height pen to be applied.
+	if ((iPenSize.iWidth == iPenSize.iHeight) || (paintMode & VG_FILL_PATH))
+		{
+		if (PreparePath(iVgPath, aClosed ? numPoints + 1 : numPoints))
+			{
+			AppendPathCommand(VG_MOVE_TO_ABS, aPoints[0].iX + 0.5f, aPoints[0].iY + 0.5f);
+			for (TInt point = 0; point < numPoints; ++point)
+				{
+				AppendPathCommand(VG_LINE_TO_ABS, aPoints[point].iX + 0.5f, aPoints[point].iY + 0.5f);	
+				}
+			if (aClosed)
+				{
+				AppendPathCommand(VG_CLOSE_PATH);
+				}
+			FinishPath(iVgPath);
+			for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+				vgDrawPath(iVgPath, (iPenSize.iWidth == iPenSize.iHeight) ? paintMode : VG_FILL_PATH);
+			}
+		}
+	
+	if ((iPenSize.iWidth != iPenSize.iHeight)
+		&& (paintMode & VG_STROKE_PATH)		
+		&& (iPenSize.iWidth != 0) && (iPenSize.iHeight != 0))
+		{
+		// Setting a pen with different width and height is not available on OpenVG, so we need to scale 
+		// the coordinates we are drawing and apply a scaling matrix that scales by the width and height 
+		// of the pen to get the effect of a pen width different width and height.
+		TSize penSize = iPenSize;
+		SetPenSize(TSize(1, 1));
+		vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+		vgScale(penSize.iWidth, penSize.iHeight);
+		
+		if (PreparePath(iVgPath, aClosed ? numPoints + 1 : numPoints))
+			{
+			AppendPathCommand(VG_MOVE_TO_ABS, (aPoints[0].iX + 0.5f)/(float)penSize.iWidth, (aPoints[0].iY + 0.5f)/(float)penSize.iHeight);
+			for (TInt point = 0; point < numPoints; ++point)
+				{
+				AppendPathCommand(VG_LINE_TO_ABS, (aPoints[point].iX + 0.5f)/(float)penSize.iWidth, (aPoints[point].iY + 0.5f)/(float)penSize.iHeight);	
+				}				
+			if (aClosed)
+				{
+				AppendPathCommand(VG_CLOSE_PATH);
+				}			
+			FinishPath(iVgPath);		
+			vgDrawPath(iVgPath, VG_STROKE_PATH);
+			}
+		
+		ResetVgMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
+		SetPenSize(penSize);
+		}
+			
+	}
+
+/**
+@see MDirectGdiEngine::DrawArc()
+@see DrawPie()
+@see DrawArc(const TRect&, const TPoint&, const TPoint&, VGUArcType)
+ */
+void CVgEngine::DrawArc(const TRect& aRect, const TPoint& aStart, const TPoint& aEnd) 
+	{	
+	DoDrawArc(aRect, aStart, aEnd, VGU_ARC_OPEN);
+	}
+
+/**
+@see MDirectGdiEngine::DrawPie()
+@see DrawArc(const TRect&, const TPoint&, const TPoint&)
+@see DrawArc(const TRect&, const TPoint&, const TPoint&, VGUArcType)
+ */
+void CVgEngine::DrawPie(const TRect& aRect, const TPoint& aStart, const TPoint& aEnd) 
+	{	
+	DoDrawArc(aRect, aStart, aEnd, VGU_ARC_PIE);
+	}
+
+/**
+@see MDirectGdiEngine::DrawEllipse()
+ */
+void CVgEngine::DrawEllipse(const TRect& aRect) 
+	{
+	// Null brush and pen, draw nothing.
+	if (iPaintMode == 0)
+		return;
+	
+	MakeEngineCurrent();	
+	VGfloat x = (aRect.iTl.iX + aRect.iBr.iX) * 0.5;
+	VGfloat y = (aRect.iTl.iY + aRect.iBr.iY) * 0.5;
+	
+	// Before any vgu command, call SetError() as this stores the current vg error state (if any) in the 
+	// driver. Some implementations of vgu clears error state so we'd lose error codes otherwise.
+	iDriver.SetError(KErrNone);
+	
+	TInt width = aRect.Width();
+	TInt height = aRect.Height();
+	
+	//If the penstyle is null and brush style is not null, then reduce the width and height by
+	//two pixels for conformation.
+	if(iPenStyle == DirectGdi::ENullPen && iBrushStyle != DirectGdi::ENullBrush)
+		{
+		width = aRect.Width() > 2 ? aRect.Width() - 2 : 1;
+		height = aRect.Height() > 2 ? aRect.Height() - 2 : 1;
+		}
+	
+	// If the pen width and height are the same then draw as normal. If they are different but we should be filling
+	// this shape we need to draw the filled area only as normal (not the outline). The outline of the shape is drawn 
+	// in the block of code below to allow the effect of a different width and height pen to be applied.
+	if ((iPenSize.iWidth == iPenSize.iHeight) || (iPaintMode & VG_FILL_PATH))
+		{
+		if (PreparePath(iVgPath, 4))
+			{
+			VGUErrorCode err = vguEllipse(iVgPath, x, y, width, height);
+			if (err == VGU_NO_ERROR)
+				{
+				for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+					vgDrawPath(iVgPath, (iPenSize.iWidth == iPenSize.iHeight) ? iPaintMode : VG_FILL_PATH);
+				}
+			else
+				{
+				SetVguError(err);
+				}
+			}
+		}
+	
+	if ((iPenSize.iWidth != iPenSize.iHeight)
+		&& (iPaintMode & VG_STROKE_PATH)		
+		&& (iPenSize.iWidth != 0) && (iPenSize.iHeight != 0))
+		{
+		// Setting a pen with different width and height is not available on OpenVG, so we need to scale 
+		// the coordinates we are drawing and apply a scaling matrix that scales by the width and height 
+		// of the pen to get the effect of a pen width different width and height.
+		TSize penSize = iPenSize;
+		SetPenSize(TSize(1, 1));
+		vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+		vgScale(penSize.iWidth, penSize.iHeight);
+		
+		VGfloat scaleX = 1.0f/(float)penSize.iWidth;
+		VGfloat scaleY = 1.0f/(float)penSize.iHeight;
+		
+		if (PreparePath(iVgPath, 4))
+			{
+			VGUErrorCode err = vguEllipse(iVgPath, x*scaleX, y*scaleY, (float)width*scaleX, (float)height*scaleY);			
+			if (err == VGU_NO_ERROR)
+				{
+				vgDrawPath(iVgPath, VG_STROKE_PATH);
+				}
+			else
+				{
+				SetVguError(err);
+				}
+			}
+		
+		ResetVgMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
+		SetPenSize(penSize);			
+		}	
+	}
+
+/**
+Given a TDisplayMode, returns the closest TDisplayMode that is pixel-for-pixel-compatible
+with an OpenVG format, such that the given TDisplayMode may be converted into the result
+without loss of colour information.
+
+@param 	aDisplayMode Pixel format to find a match for.
+
+@return Closest TDisplayMode for which there is a OpenVG-compatible match.
+ */
+static TDisplayMode ClosestVgCompatibleDisplayMode(TDisplayMode aDisplayMode)
+	{
+	switch (aDisplayMode)
+		{
+		case EGray2:
+		case EGray4:
+		case EGray16:
+			return EGray256;
+
+		case EColor16:
+		case EColor256:
+		case EColor4K:
+			return EColor64K;
+		
+		case EColor16M:
+			return EColor16MU;
+			
+		default:
+			return aDisplayMode;
+		}
+	}
+
+/**
+Converts a CFbsBitmap into a VGImage.
+If the CFbsBitmap is not a volatile bitmap, the VGImage created will be stored in the thread-wide 
+VGImage cache. If the CFbsBitmap has been touched (i.e. its data has been changed since it was last 
+used), a new VGImage will be created and will replace that currently stored in the cache. An untouched 
+bitmap will store the created VGImage in the cache upon first use, and on subsequent use (if it is 
+still untouched), will just retrieve the VGImage stored in the cache.
+
+@param aBitmap The CFbsBitmap to create a VGImage from.
+@param aImage Returns the VGImage created from the CFbsBitmap.
+@param aIsMask True if the CFbsBitmap is to be used as a mask.
+@param aOrigin Position of the first pixel in the mask bitmap.
+
+@return ETrue if the VGimage has been stored in the cache, EFalse if not.
+*/
+TBool CVgEngine::ConvertBitmapToVgImage(const CFbsBitmap& aBitmap, VGImage& aImage, TBool aIsMask, const TPoint& aOrigin)
+	{
+	TBool createImage =  EFalse;
+	TBool storeImageInCache = EFalse;
+	TBool imageCached = EFalse;
+	// Set the options createImage, storeImageInCache and imageCached depending on
+	// whether the bitmap is volatile, has been touched since last used,
+	// and whether it already exists in the cache
+	if (aBitmap.IsVolatile()) 
+		{
+		// Source bitmap is volatile and so should not be stored in cache.
+		// Therefore create image only.
+		createImage = ETrue;
+		}
+	else //bitmap not volatile
+		{
+		// Source bitmap has not changed since last used.
+		// Retrieve from cache the image created from the bitmap and the touchCount of that image.
+		aImage = iDriver.GetVgImageFromCache(aBitmap, aOrigin);
+		// If the source bitmap already has an associated VGImage stored in the cache,
+		// just use that VGImage.  Otherwise, need to create a VGImage and add it to the cache.
+		if (aImage == VG_INVALID_HANDLE)
+			{
+			// VGImage not in cache
+			// Create image, and store in cache
+			createImage = ETrue;
+			storeImageInCache = ETrue;
+			}
+		else
+			{
+			// Image already in cache
+			imageCached = ETrue;
+			}
+		}
+
+	// Create a new VGImage if needed
+	if (createImage)
+		{
+		aImage = CreateSourceVGImage(aBitmap, aIsMask, aOrigin);
+		// Error set on creation of VGImage if aImage == VG_INVALID_HANDLE.
+		}
+	// Store the VGImage in the cache if appropriate
+	if (storeImageInCache && aImage != VG_INVALID_HANDLE)
+		{
+		imageCached = iDriver.AddVgImageToCache(aBitmap, aImage, aOrigin);
+		}
+	return imageCached;
+	}
+
+
+/**
+Transforms coordinates for a TRect from Symbian Graphics to OpenVG surface coordinates.
+This is required for OpenVG operations which are not subject to user-to-surface 
+coordinate system transformations.
+
+OpenVG coordinates locate the BOTTOM LEFT corner of the object relative to an origin
+at the BOTTOM LEFT of the rendering area.
+
+Symbian Graphics coordinates locate the TOP LEFT corner of the object relative to an 
+origin located at the TOP LEFT of the rendering area.
+
+@param	aCoord		Top-left of the rectangle, in Symbian graphics coordinates.
+@param  aWidth		The width of the desired rectangle.
+@param  aHeight		The height of the desired rectangle.
+@return A TRect in OpenVG coordinates which describes a rectangle at aCoord with aWidth and aHeight.
+*/
+TRect CVgEngine::SgMetricsToVgTRect(const TPoint& aCoord, const TInt aWidth, const TInt aHeight) const
+	{
+	return TRect (TPoint (aCoord.iX + iOrigin.iX, iSize.iHeight - (aCoord.iY + aHeight) - iOrigin.iY), TSize (aWidth, aHeight));
+	}
+
+/** 
+@see MDirectGdiEngine::BitBlt()
+@see BitBltMasked(const TPoint&, const CFbsBitmap&, const TRect&, const CFbsBitmap&, TBool)
+@see BitBltMasked(const TPoint&, const CFbsBitmap&, const TRect&, const CFbsBitmap&, const TPoint&)
+ */
+void CVgEngine::BitBlt(const TPoint& aDestPos, const CFbsBitmap& aSourceBitmap, const TRect& aSourceRect)
+	{
+	if (aSourceBitmap.ExtendedBitmapType() != KNullUid)
+		{
+		iDriver.SetError(KErrNotSupported); // Not supported for extended bitmaps
+		return;
+		}
+	
+	DoVgImageDraw (TRect (aDestPos, aSourceRect.Size()), aSourceBitmap, aSourceRect);
+	}
+
+/** 
+@see MDirectGdiEngine::DrawBitmap()
+@see DrawBitmapMasked()
+ */
+void CVgEngine::DrawBitmap(const TRect& aDestRect, const CFbsBitmap& aSourceBitmap, const TRect& aSourceRect) 
+	{
+	if (aSourceBitmap.ExtendedBitmapType() != KNullUid)
+		{
+		iDriver.SetError(KErrNotSupported); // Not supported for extended bitmaps
+		return;
+		}
+	
+	DoVgImageDraw (aDestRect, aSourceBitmap, aSourceRect);
+	}
+
+
+/**
+Helper method to perform basic VgDrawImage operations, explictly optimised for the case where
+the extents of the source image equal the specified source region.
+
+@pre aSource image is a valid VG image handle.
+@pre Destination position and/or scaling has already been set in OpenVG. 
+
+@param aDestRect	 	Destination rectangle to draw to.
+@param aSourceBitmap	Source bitmap to draw.
+@param aSourceRect 		Source rectangle to render. 
+*/
+void CVgEngine::DoVgImageDraw (const TRect& aDestRect, const CFbsBitmap& aSourceBitmap, const TRect& aSourceRect)
+	{
+	MakeEngineCurrent();
+	TRect destRect(aDestRect);
+	TRect srcRect(aSourceRect);
+	if (!IntersectsClippingRegion (TRect(iOrigin, destRect.Size()))) 
+		return;
+	
+	VGImage sourceImage = VG_INVALID_HANDLE;
+	TBool imageCached = ConvertBitmapToVgImage(aSourceBitmap, sourceImage);
+	// Error set on creation of VGImage.
+	if (sourceImage == VG_INVALID_HANDLE) return;
+
+	vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+	vgTranslate(destRect.iTl.iX, destRect.iTl.iY);
+	
+	if (aDestRect.Size() != aSourceRect.Size())
+		vgScale((VGfloat)destRect.Width()/aSourceRect.Width(), (VGfloat)destRect.Height()/aSourceRect.Height());
+	
+	if(aSourceBitmap.SizeInPixels() == aSourceRect.Size())
+		{
+		for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+			vgDrawImage(sourceImage);
+		}
+	else
+		{
+		VGImage sourceImageRegion = 
+			vgChildImage(
+				sourceImage, 
+				srcRect.iTl.iX, 
+				srcRect.iTl.iY, 
+				srcRect.Width(), 
+				srcRect.Height());
+		
+		if (sourceImageRegion != VG_INVALID_HANDLE)
+			{
+			for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+				vgDrawImage(sourceImageRegion);
+
+			vgDestroyImage(sourceImageRegion);
+			}
+		}
+		
+	if (!imageCached) vgDestroyImage (sourceImage);
+	ResetVgMatrix(VG_MATRIX_IMAGE_USER_TO_SURFACE);	// Reset the transform matrix.		
+	}
+
+/** 
+@see MDirectGdiEngine::BitBltMasked()
+@see BitBltMasked(const TPoint&, const CFbsBitmap&, const TRect&, const CFbsBitmap&, TBool)
+@see BitBlt()
+ */
+void CVgEngine::BitBltMasked(
+		const TPoint& aDestPos,
+		const CFbsBitmap& aBitmap,
+		const TRect& aSourceRect,
+		const CFbsBitmap& aMask,
+		const TPoint& aMaskPt)
+	{
+	if ((aBitmap.ExtendedBitmapType() != KNullUid) || (aMask.ExtendedBitmapType() != KNullUid))
+		{
+		iDriver.SetError(KErrNotSupported); // Not supported for extended bitmaps
+		return;
+		}
+	
+	DoBitBltMasked(aDestPos, aBitmap, aSourceRect, aMask, EFalse, aMaskPt);
+	}
+
+/** 
+@see MDirectGdiEngine::BitBlt()
+@see BitBltMasked(const TPoint&, const CFbsBitmap&, const TRect&, const CFbsBitmap&, const TPoint&)
+@see BitBlt()
+ */
+void CVgEngine::BitBltMasked( 
+		const TPoint& aDestPos,
+		const CFbsBitmap& aSourceBitmap,
+		const TRect& aSourceRect,
+		const CFbsBitmap& aMaskBitmap, 
+		TBool aInvertMask)
+	{
+	if ((aSourceBitmap.ExtendedBitmapType() != KNullUid) || (aMaskBitmap.ExtendedBitmapType() != KNullUid))
+		{
+		iDriver.SetError(KErrNotSupported); // Not supported for extended bitmaps
+		return;
+		}
+	
+	DoBitBltMasked(aDestPos, aSourceBitmap, aSourceRect, aMaskBitmap, aInvertMask, TPoint(0, 0));
+	}
+
+/**
+Helper method for performing BitBltMasked().
+Note that aInvertMask is ignored if aMaskPos is not at 0,0.
+
+@see	CDirectGdiContext::BitBlt(const TPoint& aPoint, const CFbsBitmap& aBitmap, const TRect& aSourceRect);
+@see	CDirectGdiContext::BitBltMasked(const TPoint&, const CFbsBitmap&,const TRect&, const CFbsBitmap&, const TPoint&);
+
+@param	aDestPos		The destination for the top left corner of the transferred bitmap. 
+						It is relative to the top left corner of the destination bitmap, which may be the screen. 
+@param	aSourceBitmap	A memory-resident source bitmap.
+@param	aSourceRect		A rectangle defining the piece of the bitmap to be drawn, 
+						with co-ordinates relative to the top left corner of the bitmap. 
+@param	aMaskBitmap		Mask bitmap.
+@param	aInvertMask		If EFalse, a source pixel that is masked by a black pixel is not transferred to 
+						the destination rectangle. If ETrue, then a source pixel that is masked by a 
+						white pixel is not transferred to the destination rectangle. If alpha blending
+						is used instead of masking, this flag is ignored and no inversion takes place.
+						Note that this parameter is ignored if aMaskPos does not equal TPoint(0,0).
+@param	aMaskPos		The point on the mask bitmap to use as the top left corner 
+*/
+void CVgEngine::DoBitBltMasked (
+		const TPoint& aDestPos,
+		const CFbsBitmap& aSourceBitmap,
+		const TRect& aSourceRect,
+		const CFbsBitmap& aMaskBitmap,
+		TBool aInvertMask,
+		const TPoint& aMaskPos)
+	{
+	MakeEngineCurrent();
+	ResetVgMatrix(VG_MATRIX_IMAGE_USER_TO_SURFACE);
+	if (!IntersectsClippingRegion (TRect (aDestPos+iOrigin, aSourceRect.Size()))) 
+		return;
+	
+	VGImage sourceImage = VG_INVALID_HANDLE;
+	TBool imageCached = ConvertBitmapToVgImage(aSourceBitmap, sourceImage);
+	if (sourceImage == VG_INVALID_HANDLE)
+		{
+		// Error set on creation of VGImage.
+		return;
+		}
+	
+	VGImage maskImage = VG_INVALID_HANDLE;
+	TBool maskImageCached = ConvertBitmapToVgImage(aMaskBitmap, maskImage, ETrue, aMaskPos);
+	if (maskImage == VG_INVALID_HANDLE)
+		{
+		// Error set on creation of VGImage.
+		if (!imageCached)
+			{
+			vgDestroyImage(sourceImage);
+			}
+		return;
+		}
+
+	DoVgMaskedImageDraw(
+		aDestPos,
+		sourceImage,
+		aSourceBitmap.SizeInPixels(),
+		aSourceRect,
+		maskImage,
+		aMaskBitmap.SizeInPixels(),
+		aSourceRect.Size(),
+		aInvertMask);
+
+	if (!maskImageCached)
+		{
+		vgDestroyImage(maskImage);
+		}
+	if (!imageCached)
+		{
+		vgDestroyImage(sourceImage);
+		}
+	}
+
+
+/** 
+This implementation stretches the mask first, and then performs mask tiling. Another approach is to
+tile first and then perform stretching. The latter method requires more memory and stretches
+once. Results between these methods are different. When stretching first, all tiles will be completely
+uniform. When stretching last, different tiles are affected differently, based on the tile's position
+and stretch factor.
+
+@see MDirectGdiEngine::DrawBitmapMasked()
+@see DrawBitmap()
+ */
+void CVgEngine::DrawBitmapMasked(
+	const TRect& aDestRect,
+	const CFbsBitmap& aSourceBitmap,
+	const TRect& aSourceRect,
+	const CFbsBitmap& aMaskBitmap,
+	TBool aInvertMask)
+	{
+	if ((aSourceBitmap.ExtendedBitmapType() != KNullUid) || (aMaskBitmap.ExtendedBitmapType() != KNullUid))
+		{
+		iDriver.SetError(KErrNotSupported); // Not supported for extended bitmaps
+		return;
+		}
+	
+	MakeEngineCurrent();
+	TRect destRect(aDestRect);
+	if (!IntersectsClippingRegion (TRect(iOrigin, destRect.Size())))
+		{
+		return;
+		}
+
+	// Create source image
+	VGImage sourceImage = VG_INVALID_HANDLE;
+	TBool imageCached = ConvertBitmapToVgImage(aSourceBitmap, sourceImage);
+	// Return if VGImage failed to be created (error set on creation of VGImage).
+	if (sourceImage == VG_INVALID_HANDLE)
+		{
+		return;
+		}
+		
+	// Convert aMask to a VGImage.
+	VGImage maskImage = VG_INVALID_HANDLE;
+	TBool maskImageCached = ConvertBitmapToVgImage(aMaskBitmap, maskImage, ETrue);
+	// Error set on creation of VGImage if mask == VG_INVALID_HANDLE
+
+	if (maskImage != VG_INVALID_HANDLE)
+		{
+		TSize destSize = destRect.Size();
+		TSize sourceSize = aSourceRect.Size();
+		if ((destSize.iWidth == sourceSize.iWidth) && (destSize.iHeight == sourceSize.iHeight))
+			{
+			// No scaling of masked bitmap involved
+			DoVgMaskedImageDraw(
+					destRect.iTl,
+					sourceImage,
+					aSourceBitmap.SizeInPixels(),
+					aSourceRect,
+					maskImage,
+					aMaskBitmap.SizeInPixels(),
+					destSize,
+					aInvertMask);
+			}
+		else
+			{
+			// Unfortunately, the current implementation of VG does not support
+			// mask scaling. So, we render the mask into a VGImage pbuffer surface,
+			// and apply user to surface scaling to get a stretch. The stretched
+			// mask is then used for rendering.
+
+			// Generate the VGImage to act as a pbuffer surface and receive the stretched mask.
+			const TSize maskSizeInPixels = aMaskBitmap.SizeInPixels();
+			const VGImageFormat vgFormat = MapToVgDisplayMode(ClosestVgCompatibleDisplayMode(aMaskBitmap.DisplayMode()));
+			TInt scaledMaskWidth = Scale(maskSizeInPixels.iWidth,destSize.iWidth,sourceSize.iWidth);
+			TInt scaledMaskHeight = Scale(maskSizeInPixels.iHeight,destSize.iHeight,sourceSize.iHeight);
+			VGImage stretchedMask = DoVgCreateImage(vgFormat,
+											scaledMaskWidth,
+											scaledMaskHeight,
+											VG_IMAGE_QUALITY_NONANTIALIASED);
+	 
+			if (stretchedMask != VG_INVALID_HANDLE)
+				{
+				// Get a configuration handle that is compatible with the mask pixel format.
+				EGLConfig utilConfig = 0;
+				TInt err = TConfigHelper::GetConfigForFbsBitmap (aMaskBitmap, utilConfig);
+				if (err == KErrNone)
+					{
+					TBool eglSuccess = EFalse;
+					EGLDisplay eglDisplay = iDriver.EglDisplay();
+					EGLSurface lastSurface = eglGetCurrentSurface(EGL_DRAW);
+
+					// Create a Pbuffer surface from the stretched mask VGImage.
+					EGLSurface utilSurface = eglCreatePbufferFromClientBuffer(
+						eglDisplay, 
+						EGL_OPENVG_IMAGE,
+						static_cast<EGLClientBuffer>(stretchedMask), 
+						utilConfig,
+						NULL);
+					
+					if (utilSurface != EGL_NO_SURFACE)
+						{
+						EGLContext lastContext = eglGetCurrentContext();
+						// Create config. compatible context.
+						EGLContext utilContext = eglCreateContext(eglDisplay, utilConfig, lastContext, NULL);	
+					
+						if (utilContext != EGL_NO_CONTEXT)
+							{
+							// Make the utility surface and context current, and stretch the mask.
+							if (eglMakeCurrent(eglDisplay, utilSurface, utilSurface, utilContext) == EGL_TRUE)
+								{
+								// Set up the scaling transform for the current surface.
+								vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+								// Scaling factors for x and y.
+								VGfloat xScale = ((VGfloat)destSize.iWidth/sourceSize.iWidth);
+								VGfloat yScale = ((VGfloat)destSize.iHeight/sourceSize.iHeight);
+								vgScale(xScale, yScale);
+								
+								// Render the stretched mask.
+								vgDrawImage(maskImage);
+								ResetVgMatrix(VG_MATRIX_IMAGE_USER_TO_SURFACE);
+								
+								// All done, make current the pre-existing rendering state.
+								eglMakeCurrent(eglDisplay, lastSurface, lastSurface, lastContext);
+								
+								eglSuccess = ETrue;
+								}
+							eglDestroyContext(eglDisplay, utilContext);
+							}
+						eglDestroySurface(eglDisplay, utilSurface);
+						}	
+					
+					if (eglSuccess)
+						{
+						DoVgMaskedImageDraw(destRect.iTl, sourceImage, aSourceBitmap.SizeInPixels(),
+											aSourceRect, stretchedMask,	maskSizeInPixels, destSize,	aInvertMask);
+						}
+					else
+						{						
+						// coverity[check_return]
+						// coverity[unchecked_value]
+						LogEglError();
+						}
+					}				
+				else
+					{
+					iDriver.SetError(err);
+					}
+				vgDestroyImage (stretchedMask);
+				}
+			if (!maskImageCached) vgDestroyImage (maskImage);
+			}
+		}
+	if (!imageCached) vgDestroyImage(sourceImage);
+	}
+
+/** 
+Helper method that implements the core blitting functionality.
+
+@param	aDestPos	The destination for the top left corner of the transferred bitmap. 
+					It is relative to the top left corner of the destination bitmap, which may be the screen. 
+@param	aSourceImage A valid VGImage to draw.
+@param  aSourceImageSize Extents of source bitmap.
+@param	aSourceRect	A rectangle defining the piece of the bitmap to be drawn, 
+					with co-ordinates relative to the top left corner of the bitmap. 
+@param	aScaledMaskImage A valid mask VGImage - pre-scaled, ready for rendering.
+@param	aSrcMaskSize The size of the (unscaled) mask image.
+@param	aXscale		Scaling factor to apply to x axis (already applied to mask).
+@param	aYscale		Scaling factor to apply to y axis (already applied to mask).
+@param	aDestSize	The size of the destination (used for calculating any scaling) 
+@param	aInvertMask	If EFalse, a source pixel that is masked by a black pixel 
+					is not transferred to the destination rectangle. If ETrue, then a source 
+					pixel that is masked by a white pixel is not transferred to the destination 
+					rectangle. 
+
+@pre	The rendering target has been activated. aBitmap and aMaskBitmap are not NULL and hold Handles. 
+		Destination rectangle extents must intersect clipping region.
+		aSourceImage is a valid VGImage handle.
+@post	Request to draw the masked bitmap content has been accepted. 
+		There is no guarantee that the request has been processed when the method returns.
+ */
+void CVgEngine::DoVgMaskedImageDraw(
+		const TPoint& aDestPos,
+		VGImage aSourceImage,
+		const TRect& aSourceImageSize,
+		const TRect& aSourceRect,
+		const VGImage aScaledMaskImage,
+		const TSize& aSrcMaskSize,
+		const TSize& aDestSize,
+		TBool aInvertMask) 
+	{
+	TBool destroySourceImageAtEnd = EFalse;
+
+	if(aSourceImageSize != aSourceRect)
+		{
+		aSourceImage = 
+			vgChildImage(
+				aSourceImage, 
+				aSourceRect.iTl.iX, 
+				aSourceRect.iTl.iY, 
+				aSourceRect.Width(), 
+				aSourceRect.Height());
+
+		if (aSourceImage == VG_INVALID_HANDLE) return;
+		destroySourceImageAtEnd = ETrue;
+		}
+
+	TBool maskOK = EFalse;
+	TSize sourceSize = aSourceRect.Size();
+	TRect destRect(aDestPos, TSize(Scale(aSourceRect.Width(),aDestSize.iWidth,sourceSize.iWidth),
+										Scale(aSourceRect.Height(),aDestSize.iHeight,sourceSize.iHeight)));
+	// VG does not provide mask tiling...we currently perform multiple
+	// vgMask operations to implement tiling. It should be possible to use
+	// pattern tiling to render the mask to a surface, convert surface region
+	// to VGImage and apply that as a mask (to take advantage of native VG
+	// tiling), though cost/benefit is has not yet been determined.
+	// NOTE: It may be worth optimising for cases where xScale or yScale equal one.
+
+	TRect destVgRect = SgMetricsToVgTRect(aDestPos, destRect.Width(), destRect.Height());
+
+	if (aScaledMaskImage != VG_INVALID_HANDLE)
+		{
+		const TSize scaledMaskSize(Scale(aSrcMaskSize.iWidth,aDestSize.iWidth,sourceSize.iWidth),
+										Scale(aSrcMaskSize.iHeight,aDestSize.iHeight,sourceSize.iHeight));
+		if (scaledMaskSize.iHeight > 0 && scaledMaskSize.iWidth > 0)
+			{
+			maskOK = ETrue;
+			// Determine mask image offset for rendering.
+			TInt scaledMaskXOffset = Scale(aSourceRect.iTl.iX%aSrcMaskSize.iWidth,aDestSize.iWidth,sourceSize.iWidth);
+
+			// Sg coordinates are relative to top left, Vg are reletive to bottom left. As we
+			// tile from the bottom up we subtract from maskSize.iHeight to get the bottom edge
+			// offset.
+			TInt scaledMaskYOffset = (aSourceRect.iTl.iY + aSourceRect.Height()) % aSrcMaskSize.iHeight;
+			if (scaledMaskYOffset != 0)
+				{
+				scaledMaskYOffset = Scale(aSrcMaskSize.iHeight-scaledMaskYOffset,aDestSize.iHeight,sourceSize.iHeight);
+				}
+
+			// If inverting the mask, we use a difference operation against the existing mask, so 
+			// we need to ensure the existing mask is set to the correct state.
+			// Fill the existing mask so that it is completly transparent (set to all ones).
+			if(aInvertMask)
+				{
+				vgMask(
+					VG_INVALID_HANDLE, 
+					VG_FILL_MASK, 
+					destVgRect.iTl.iX, 
+					destVgRect.iTl.iY, 
+					destVgRect.Width(), 
+					destVgRect.Height());			
+				}
+		
+			VGMaskOperation vgMaskOp = aInvertMask ? VG_SUBTRACT_MASK : VG_SET_MASK;
+			// NOTE: in VG destVgRect.iTl is physically at the bottom and destVgRect.iBr at the top
+			for (
+				TInt maskY = destVgRect.iTl.iY - scaledMaskYOffset; 
+				maskY < destVgRect.iBr.iY; 
+				maskY += scaledMaskSize.iHeight)
+				{
+				for (
+					TInt maskX = destVgRect.iTl.iX - scaledMaskXOffset;
+					maskX < destVgRect.iBr.iX;
+					maskX += scaledMaskSize.iWidth)
+					{
+					vgMask(
+						aScaledMaskImage, 
+						vgMaskOp, 
+						maskX,
+						maskY, 
+						scaledMaskSize.iWidth,
+						scaledMaskSize.iHeight);
+					}
+				}
+			}
+		}		
+	
+	// Set up translation and scale for the current surface - note that translation must
+	// occur first, as is unscaled.
+	vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+	vgTranslate(aDestPos.iX, aDestPos.iY);
+	VGfloat xScale = ((VGfloat)aDestSize.iWidth/sourceSize.iWidth);
+	VGfloat yScale = ((VGfloat)aDestSize.iHeight/sourceSize.iHeight);
+	vgScale(xScale, yScale);
+	
+	//  Rather than bracketing vgDrawImage with VG_MASKING on/off we may want to always enable masking,
+	//  and remove the mask when finished:
+	//  vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, iRenderingTarget->Size().iWidth, iRenderingTarget->Size().iHeight);
+	//  If the mask is not removed in some way, then subsequent rendering operations which intersect with the
+	//  masking region will be affected.
+	if (maskOK) 
+		{
+		vgSeti (VG_MASKING, VG_TRUE);
+		for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+			vgDrawImage(aSourceImage);
+		vgSeti (VG_MASKING, VG_FALSE);
+		}
+	else
+		{
+		for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+			vgDrawImage(aSourceImage);
+		}
+	// Reset the transform matrix.
+	ResetVgMatrix(VG_MATRIX_IMAGE_USER_TO_SURFACE);
+	
+	if (destroySourceImageAtEnd)
+		{
+		vgDestroyImage (aSourceImage);
+		}
+	}
+
+/** 
+@see MDirectGdiEngine::DrawResource(const TPoint&, const RDirectGdiDrawableSource&, DirectGdi::TGraphicsRotation)
+@see DrawResource(const TRect&, const RDirectGdiDrawableSource&, const TRect&, DirectGdi::TGraphicsRotation)
+@see DrawResource(const TRect&, const RDirectGdiDrawableSource&, const TDesC8&)
+ */
+void CVgEngine::DrawResource(const TPoint& aPos, const RDirectGdiDrawableSource& aSource, DirectGdi::TGraphicsRotation aRotation)
+	{
+	MakeEngineCurrent();
+	
+	CDirectGdiImageSourceImpl* source = iDriver.GetImageSourceFromHandle(aSource.Handle());
+	if (source)
+		{			
+		const TSize sourceSize = source->Size();				
+		
+		if ((sourceSize.iWidth > 0) && (sourceSize.iHeight > 0))
+			{
+			VGImage vgImage = source->VgImage();
+			if (vgImage != VG_INVALID_HANDLE)
+				{
+				vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+				
+				TPoint pos(aPos);
+				
+			
+				if (aRotation == DirectGdi::EGraphicsRotationNone ||
+					aRotation == DirectGdi::EGraphicsRotation180)
+					{
+					// Pixel-data in EGLImages appears to be upside down due to the Y-inversion 
+					// effect of the Identity matrix.  Therefore must undo the Y-inversion here 
+					// and adjust destination rect accordingly.
+					pos.iY = iSize.iHeight - aPos.iY - sourceSize.iHeight - iOrigin.iY;
+					pos.iX += iOrigin.iX;
+					vgLoadIdentity();
+					}
+				else
+					{
+					// But if rotation is 90 or 270 degrees we need to mirror in the X-axis
+					// and adjust destination translation accordingly.
+					vgScale(-1, 1);
+					}
+							
+				switch (aRotation)
+					{				
+					case DirectGdi::EGraphicsRotation90:
+						vgTranslate(-pos.iX, pos.iY);
+						vgRotate(90.0f);
+						break;
+					case DirectGdi::EGraphicsRotation180:
+						vgTranslate(pos.iX+sourceSize.iWidth, pos.iY+sourceSize.iHeight);
+						vgRotate(180.0f);				
+						break;
+					case DirectGdi::EGraphicsRotation270:
+						vgTranslate(-pos.iX-sourceSize.iHeight, pos.iY+sourceSize.iWidth);
+						vgRotate(270.0f);				
+						break;
+					default:
+						// No rotation
+						vgTranslate(pos.iX, pos.iY);									
+						break;
+					}
+				
+				for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+					vgDrawImage(vgImage);				
+				
+				ResetVgMatrix(VG_MATRIX_IMAGE_USER_TO_SURFACE);
+				}
+			}
+		}
+	}
+
+/** 
+@see MDirectGdiEngine::DrawResource(const TRect&, const RDirectGdiDrawableSource&, DirectGdi::TGraphicsRotation)
+ */
+void CVgEngine::DrawResource(const TRect& aDestRect,
+		const RDirectGdiDrawableSource& aSource,
+		DirectGdi::TGraphicsRotation aRotation)
+	{
+	CDirectGdiImageSourceImpl* source = iDriver.GetImageSourceFromHandle(aSource.Handle());
+	if (source)
+		{		
+		TRect srcRect(TPoint(0, 0), source->Size());		
+		DoDrawResource(aDestRect, source, srcRect, aRotation);		
+		}
+	}
+
+/** 
+@see MDirectGdiEngine::DrawResource(const TRect&, const RDirectGdiDrawableSource&, const TRect&, DirectGdi::TGraphicsRotation)
+ */
+void CVgEngine::DrawResource(const TRect& aDestRect,
+							const RDirectGdiDrawableSource& aSource,
+							const TRect& aSourceRect,
+							DirectGdi::TGraphicsRotation aRotation)
+	{	
+	CDirectGdiImageSourceImpl* source = iDriver.GetImageSourceFromHandle(aSource.Handle());
+	if (source)
+		{
+		// check source rectangle is fully contained within the image resource extent before drawing
+		TSize size = source->Size();				
+		if ((aSourceRect.iTl.iX < 0) 
+			|| (aSourceRect.iTl.iY < 0) 
+			|| (aSourceRect.iBr.iX > size.iWidth) 
+			|| (aSourceRect.iBr.iY > size.iHeight)
+			|| (aSourceRect.Width() <= 0) 
+			|| (aSourceRect.Height() <= 0))
+			{
+			iDriver.SetError(KErrArgument);
+			return;
+			}
+						
+		if (((aSourceRect.Width() == aDestRect.Width())
+			&& (aSourceRect.Height() == aDestRect.Height())
+			&& (aRotation == DirectGdi::EGraphicsRotationNone || aRotation == DirectGdi::EGraphicsRotation180))
+			||
+			((aSourceRect.Width() == aDestRect.Height())
+			&& (aSourceRect.Height() == aDestRect.Width())
+			&& (aRotation == DirectGdi::EGraphicsRotation90 || aRotation == DirectGdi::EGraphicsRotation270)))
+			{
+			// No scaling
+			DrawResource(TPoint(aDestRect.iTl.iX, aDestRect.iTl.iY), aSource, aRotation);
+			}
+		else
+			{
+			MakeEngineCurrent();			
+			DoDrawResource(aDestRect, source, aSourceRect, aRotation);												
+			}
+		}		
+	}
+
+/** 
+This method only supports drawing of image sources as Drawables. An attempt to draw
+a Drawable that is not an image will result in a panic.
+
+@see MDirectGdiEngine::DrawResource(const TRect&, const RDirectGdiDrawableSource&, const TDesC8&)
+
+@panic DGDIAdapter 1, if an attempt is made to draw a drawable that is not an image source.
+ */
+void CVgEngine::DrawResource(
+			const TRect& aDestRect,
+			const RDirectGdiDrawableSource& aSource,
+			const TDesC8& /*aParam*/)
+	{
+	MakeEngineCurrent();
+	
+	// Check to see if the passed drawable is actually an image as we only support drawing of images at present
+	if (iDriver.IsImageSource(aSource.Handle()))
+		{
+		CDirectGdiImageSourceImpl* source = iDriver.GetImageSourceFromHandle(aSource.Handle());
+		if (source)
+			{		
+			DoDrawResource(aDestRect, source, DirectGdi::EGraphicsRotationNone);
+			}
+		}
+	else
+		{
+		// This method only supports drawing image sources at present
+		GRAPHICS_ASSERT_ALWAYS(0, EDirectGdiPanicNotImplemented);
+		}
+	}
+
+/**
+@see MDirectGdiEngine::BeginDrawGlyph()
+
+Sets the necessary OpenVG and engine state ready for receiving DrawGlyph() commands.
+Any OpenVG state that is common for all DrawGlyph() operations are set.
+ */
+void CVgEngine::BeginDrawGlyph()
+	{
+	MakeEngineCurrent();	
+	vgSetPaint(iTextBrush, VG_FILL_PATH);
+	vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+#ifdef DRAWGLYPH_MULTIPLY_MODE
+	vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_MULTIPLY);
+#else
+	vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_STENCIL);
+#endif
+	
+#ifdef DRAWGLYPH_BUFFERED
+	iDrawGlyphCount = 0;
+#endif
+	}
+
+/**
+Draws Glyph image to the given position and orientation. 
+The function crops the output image to the clipping rectangle specified as a parameter. 
+If the clipping region is defined on the current context, it will also be taken into consideration 
+
+@param	aScrPos				Position to start drawing glyph after rotation has been applied (if necessary).
+@param	aChar				Character being drawn. Signifies general Unicode character value.
+@param	aGlyphImage			Pointer to the glyph image data.
+@param	aGlyphBitmapType	Type of bitmap format.
+@param	aGlyphImageSize		Glyph image size.
+@param	aScrClipRect			Clipping rect.
+@param	aRotation			Rotation specifying how the glyph will be drawn. The number can only be divisible by 90 degrees, 
+							i.e. horizontal and vertical rotation.
+
+@see  CFont::TTextDirection
+@see MDirectGdiEngine::DrawGlyph()
+
+@pre	The rendering target has been activated.
+@post	Request to draw the Glyph has been accepted.
+@panic  DGDIAdapter 8, if aClipRect is empty (debug-only).
+@panic  DGDIAdapter 61, if font glyph image storage does not exist (debug-only).
+*/
+void CVgEngine::DrawGlyph(
+			const TPoint& aScrPos, 
+			const TChar aChar, 
+			const TUint8* aGlyphImage,
+			const TGlyphBitmapType aGlyphBitmapType,
+			const TSize& aGlyphImageSize,
+			const TRect& aScrClipRect,			
+			const DirectGdi::TGraphicsRotation aRotation)
+	{
+	GRAPHICS_ASSERT_DEBUG(!aScrClipRect.IsEmpty(), EDirectGdiPanicInvalidRegion);
+	GRAPHICS_ASSERT_DEBUG(iFontGlyphImageStorage, EDirectGdiPanicGlyphImageStorageNotCreated);
+	
+	TPoint pos = aScrPos;
+	pos += iDrawOrigin;
+	TRect clipRect = aScrClipRect;
+	clipRect.iTl += iDrawOrigin;
+	clipRect.iBr += iDrawOrigin;
+	
+	if(	aGlyphImageSize.iHeight <= 0 ||	aGlyphImageSize.iWidth <= 0 ||
+		!clipRect.Intersects(iTargetRegion.BoundingRect()) || !iRegionManager.Intersects(clipRect))
+		{
+		// Just leave silently, as spaces could be passed with empty size.
+		return;
+		}
+	
+	// Clip the glyph against the target and the clipping rects.
+	// Calculate the axis-aligned bounding box of the glyph.
+	TRect glyphBoundingBox;
+	switch(aRotation)
+		{
+		case DirectGdi::EGraphicsRotation90:
+			glyphBoundingBox = TRect(TPoint(1+pos.iX-aGlyphImageSize.iHeight, pos.iY), TSize(aGlyphImageSize.iHeight, aGlyphImageSize.iWidth));
+			break;
+		case DirectGdi::EGraphicsRotation180:
+			glyphBoundingBox = TRect(TPoint(pos.iX-aGlyphImageSize.iHeight, pos.iY-aGlyphImageSize.iWidth), aGlyphImageSize);
+			break;
+		case DirectGdi::EGraphicsRotation270:
+			glyphBoundingBox = TRect(TPoint(pos.iX, 1+pos.iY-aGlyphImageSize.iWidth), TSize(aGlyphImageSize.iHeight, aGlyphImageSize.iWidth));
+			break;
+		default:
+			glyphBoundingBox = TRect(pos, aGlyphImageSize);
+			break;
+		}
+	if (!glyphBoundingBox.Intersects(iTargetRegion.BoundingRect()) || !iRegionManager.Intersects(glyphBoundingBox))
+		{
+		return;
+		}
+#ifdef DRAWGLYPH_BUFFERED
+	iDrawGlyphCommand[iDrawGlyphCount].pos = pos;
+	iDrawGlyphCommand[iDrawGlyphCount].aChar = aChar;
+	iDrawGlyphCommand[iDrawGlyphCount].aGlyphBitmapType = aGlyphBitmapType;
+	iDrawGlyphCommand[iDrawGlyphCount].aGlyphImageSize = aGlyphImageSize;
+	iDrawGlyphCommand[iDrawGlyphCount].aClipRect = clipRect;
+	iDrawGlyphCommand[iDrawGlyphCount].aRotation = aRotation;
+	iDrawGlyphCommand[iDrawGlyphCount].aGlyphImage = const_cast<TUint8*>(aGlyphImage);	
+	++iDrawGlyphCount;	
+	if (iDrawGlyphCount == KMaxGlyphs)
+		{
+		FlushDrawGlyphs();
+		iDrawGlyphCount = 0;
+		}
+#else	
+	VGImage foreground = VG_INVALID_HANDLE;
+	VGImage outline = VG_INVALID_HANDLE;
+	VGImage shadow = VG_INVALID_HANDLE;
+
+	TInt err = iFontGlyphImageStorage -> GlyphImage(iFontId, aChar, aGlyphBitmapType, aGlyphImage, aGlyphImageSize, &foreground, &shadow, &outline);
+	if(err != KErrNone)
+		{
+		iDriver.SetError(err);
+		if(err == KErrNoMemory)
+			{
+			if((foreground == VG_INVALID_HANDLE) || 
+				((aGlyphBitmapType == EFourColourBlendGlyphBitmap) && ((shadow == VG_INVALID_HANDLE) || (outline == VG_INVALID_HANDLE))))
+				{
+				return;
+				}
+			}
+		else
+			{
+			return;
+			}
+		}
+	
+	RRegion oldClippingRegion;
+	oldClippingRegion.Copy(iRegionManager.ClippingRegion());
+	iRegionManager.ClipTo(clipRect);
+	
+	//  Load the matrix which converts Symbian coordinate system to OpenVG coordinate system
+	vgLoadMatrix(Identity());
+	if(aRotation == DirectGdi::EGraphicsRotation90)
+		{
+		vgTranslate(pos.iX+1, pos.iY);
+		vgRotate(90.0f);
+		}
+	else if(aRotation == DirectGdi::EGraphicsRotation270)
+		{
+		vgTranslate(pos.iX, pos.iY+1);
+		vgRotate(270.0f);
+		}
+	else
+		{
+		vgTranslate(pos.iX, pos.iY);
+		}		
+
+	switch(aGlyphBitmapType)
+		{
+		case EMonochromeGlyphBitmap:
+		case EAntiAliasedGlyphBitmap:
+			for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+				vgDrawImage(foreground);
+			break;
+		case EFourColourBlendGlyphBitmap:
+			{
+			SetVgPaintColor(iTextBrush, iBrushColor);
+			for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+				vgDrawImage(foreground);
+	
+			SetVgPaintColor(iTextBrush, iTextShadowColor);
+			for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+				vgDrawImage(shadow);
+	
+			SetVgPaintColor(iTextBrush, iPenColor);
+			for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+				vgDrawImage(outline);
+			break;
+			}
+		}
+
+	// Restore the clipping manager to its previous state.
+	iRegionManager.SetClippingRegion(oldClippingRegion);
+	oldClippingRegion.Close();
+#endif
+	}
+
+/**
+@see MDirectGdiEngine::EndDrawGlyph()
+
+Undoes any OpenVG or engine state changes made in BeginDrawGlyph().
+ */
+void CVgEngine::EndDrawGlyph()
+	{
+#ifdef DRAWGLYPH_BUFFERED
+	FlushDrawGlyphs();
+	iDrawGlyphCount = 0;
+#endif
+	vgLoadMatrix(Identity());
+	if (iOrigin != TPoint(0,0))
+		{
+		vgTranslate(iOrigin.iX, iOrigin.iY);
+		}
+		
+	vgSetPaint(iBrush, VG_FILL_PATH);
+	vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
+	}
+
+#ifdef DRAWGLYPH_BUFFERED
+void CVgEngine::FlushDrawGlyphs()
+	{
+	VGImage foreground[KMaxGlyphs];
+	Mem::FillZ(foreground, iDrawGlyphCount*sizeof(VGImage));
+	VGImage outline[KMaxGlyphs];
+	VGImage shadow[KMaxGlyphs];
+	
+	for (TInt glyph = 0; glyph < iDrawGlyphCount; ++glyph)
+		{
+		if (foreground[glyph] == 0)
+			{			
+			TSize aGlyphImageSize = iDrawGlyphCommand[glyph].aGlyphImageSize;
+			TChar aChar = iDrawGlyphCommand[glyph].aChar;
+			TGlyphBitmapType aGlyphBitmapType = iDrawGlyphCommand[glyph].aGlyphBitmapType;
+			TUint8* aGlyphImage = iDrawGlyphCommand[glyph].aGlyphImage;
+		
+			VGImage foreground1 = VG_INVALID_HANDLE;
+			VGImage outline1 = VG_INVALID_HANDLE;
+			VGImage shadow1 = VG_INVALID_HANDLE;
+		
+			TInt err = iFontGlyphImageStorage -> GlyphImage(iFontId, aChar, aGlyphBitmapType, aGlyphImage, aGlyphImageSize, &foreground1, &shadow1, &outline1);
+			if(err != KErrNone)
+				{
+				iDriver.SetError(err);
+				if(err == KErrNoMemory)
+					{
+					if((foreground1 == VG_INVALID_HANDLE) || 
+						((aGlyphBitmapType == EFourColourBlendGlyphBitmap) && ((shadow1 == VG_INVALID_HANDLE) || (outline1 == VG_INVALID_HANDLE))))
+						{
+						return;
+						}
+					}
+				else
+					{
+					return;
+					}
+				}
+			
+			foreground[glyph] = foreground1;
+			outline[glyph] = outline1;
+			shadow[glyph] = shadow1;
+			
+			for (TInt nextGlyph = glyph+1; nextGlyph < iDrawGlyphCount; nextGlyph++)
+				{
+				if (foreground[nextGlyph] == 0)
+					{
+					if (iDrawGlyphCommand[glyph].SameGlyph(iDrawGlyphCommand[nextGlyph]))
+						{
+						foreground[nextGlyph] = foreground[glyph];
+						outline[nextGlyph] = outline[glyph];
+						shadow[nextGlyph] = shadow[glyph];
+						}
+					}
+				}
+			}
+		}
+		
+	RRegion oldClippingRegion;
+	oldClippingRegion.Copy(iRegionManager.ClippingRegion());
+	vgLoadMatrix(Identity());
+	TPoint lastPos;
+	for (TInt glyph = 0; glyph < iDrawGlyphCount; ++glyph)
+		{
+		TGlyphBitmapType aGlyphBitmapType = iDrawGlyphCommand[glyph].aGlyphBitmapType;
+		TRect aClipRect = iDrawGlyphCommand[glyph].aClipRect;
+		DirectGdi::TGraphicsRotation aRotation = iDrawGlyphCommand[glyph].aRotation;
+		TPoint aPos = iDrawGlyphCommand[glyph].pos;
+		
+		iRegionManager.ClipTo(aClipRect);
+		
+		//  Load the matrix which converts Symbian coordinate system to OpenVG coordinate system
+		
+		if(aRotation == DirectGdi::EGraphicsRotation90)
+			{
+			vgTranslate(aPos.iX+1, aPos.iY);
+			vgRotate(90.0f);
+			}
+		else if(aRotation == DirectGdi::EGraphicsRotation270)
+			{
+			vgTranslate(aPos.iX, aPos.iY+1);
+			vgRotate(270.0f);
+			}
+		else
+			{
+			//vgTranslate(aPos.iX, aPos.iY);
+			vgTranslate(aPos.iX-lastPos.iX, aPos.iY - lastPos.iY);
+			lastPos = aPos;
+			}		
+	
+		switch(aGlyphBitmapType)
+			{
+			case EMonochromeGlyphBitmap:
+			case EAntiAliasedGlyphBitmap:
+				for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+					vgDrawImage(foreground[glyph]);
+				break;
+			case EFourColourBlendGlyphBitmap:
+				{
+				SetVgPaintColor(iTextBrush, iBrushColor);
+				for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+					vgDrawImage(foreground[glyph]);
+		
+				SetVgPaintColor(iTextBrush, iTextShadowColor);
+				for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+					vgDrawImage(shadow[glyph]);
+		
+				SetVgPaintColor(iTextBrush, iPenColor);
+				for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+					vgDrawImage(outline[glyph]);
+				break;
+				}
+			}
+		
+		// Restore the clipping manager to its previous state.
+		iRegionManager.SetClippingRegion(oldClippingRegion);
+		}
+	oldClippingRegion.Close();
+	}
+#endif
+
+/**
+@see MDirectGdiEngine::CopyRect()
+ */
+void CVgEngine::CopyRect(const TPoint& aOffset, const TRect& aRect)
+	{
+	MakeEngineCurrent();
+
+	// Transformations, masking and blending are not applied.
+	// So need to convert to VG coordinate system.
+	// i.e. Need Bottom-Left coord of aRect in VG's coordinates.
+	// Also need to allow for drawing engine coordinate system (iOrigin)
+	const TPoint sourcePoint = ConvertToVgCoords(TPoint(aRect.iTl.iX, aRect.iBr.iY) + iOrigin);
+	// Scissoring is applied to destination, but does not affect reading of pixels.
+	for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+		vgCopyPixels(sourcePoint.iX + aOffset.iX, sourcePoint.iY - aOffset.iY,	// destination point
+						sourcePoint.iX, sourcePoint.iY,							// source point
+						aRect.Width(), aRect.Height());							// size of rect to copy
+	}
+
+/**
+@see MDirectGdiEngine::ExternalizeL()
+@see InternalizeL()
+ */
+void CVgEngine::ExternalizeL(RWriteStream& aWriteStream) 
+	{
+	aWriteStream.WriteUint32L(iPaintMode);
+	aWriteStream << iLinePos;
+	}
+
+/**
+@see MDirectGdiEngine::InternalizeL()
+@see ExternalizeL()
+ */
+void CVgEngine::InternalizeL(RReadStream& aReadStream)
+	{
+	iPaintMode = aReadStream.ReadUint32L();
+	aReadStream >> iLinePos;
+	}
+
+/**
+@see MDirectGdiEngine::GetInterface()
+ */
+TInt CVgEngine::GetInterface(TUid aInterfaceId, TAny*& aInterface)
+	{
+	aInterface = NULL;
+	TInt err = KErrNone;
+	switch (aInterfaceId.iUid)
+		{
+		case KDirectGdiGetGlyphStorageUid:
+			{
+			aInterface = static_cast<MFontGlyphImageStorage*> (iDriver.FontGlyphImageStorage());
+			break;	
+			}
+		case KDirectGdiVgImageCacheUid:
+			{
+			aInterface =  static_cast<MVgImageCache*> (iDriver.VgImageCache());
+			break;
+			}
+		case KDrawDeviceOriginInterfaceID:
+			{
+			aInterface = static_cast<MDrawDeviceOrigin*>(this);
+			break;
+			}
+		default:
+			err = KErrNotSupported;
+			break;
+		}
+	return err;
+	}
+
+/**
+Converts a point from the Symbian OS graphics coordinate system to the OpenVG coordinate system.
+
+The Symbian OS coordinate system's x-axis increases positively from the origin rightwards.
+The y-axis increases positively from the origin downwards.
+
+The OpenVG coordinate system's x-axis increases positively from the origin rightwards.
+The y-axis increases positively from the origin upwards.
+
+Therefore a point (X,Y) in the Symbian OS coordinate system would be equivalent to a point
+(X',Y') in the OpenVG coordinate system by the following transformations:
+X' = X
+Y' = (Height of rendering target) - Y
+
+@param	aPoint A point specified in the Symbian OS graphics coordinate system.
+
+@return The point specified in the OpenVG-specific coordinate system.
+ */
+const TPoint CVgEngine::ConvertToVgCoords(const TPoint& aPoint)
+	{
+	MakeEngineCurrent();
+	TInt targetHeight = iSize.iHeight;
+	return TPoint(aPoint.iX, targetHeight - aPoint.iY);
+	}
+
+/**
+Converts the position of a rectangle from the Symbian OS graphics coordinate system to the 
+OpenVG coordinate system.
+
+The Symbian OS coordinate system's x-axis increases positively from the origin rightwards.
+The y-axis increases positively from the origin downwards.
+A rectangle's position is specified by the top-left coordinate.
+
+The OpenVG coordinate system's x-axis increases positively from the origin rightwards.
+The y-axis increases positively from the origin upwards.
+A rectangle's position is specified by the bottom-left coordinate.
+
+A point (X,Y) in the Symbian OS coordinate system would be equivalent to point
+(X',Y') in the OpenVG coordinate system by the following transformations:
+X' = X
+Y' = (Height of rendering target) - Y
+
+@param	aRect	A rectangle whose position is to be converted for use in OpenVG.
+
+@return The bottom-left point of the rectangle, specified in the OpenVG specific coordinate system.
+ */
+const TPoint CVgEngine::ConvertToVgCoords(const TRect& aRect)
+	{
+	MakeEngineCurrent();
+	TInt targetHeight = iSize.iHeight;
+	return TPoint(aRect.iTl.iX, targetHeight - aRect.iBr.iY);
+	}
+
+/**
+Resets the user-to-surface OpenVG matrices to the default system matrix.
+ */
+void CVgEngine::ResetVgMatrix()
+	{
+	ResetVgMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
+	ResetVgMatrix(VG_MATRIX_IMAGE_USER_TO_SURFACE);
+	}
+
+/**
+Resets an OpenVG matrix to the default system matrix. Current origin offset applies.
+@param aMatrixMode The OpenVG matrix being reset.
+ */
+void CVgEngine::ResetVgMatrix(const VGMatrixMode aMatrixMode)
+	{
+	vgSeti(VG_MATRIX_MODE, aMatrixMode);
+	//  Load matrix which converts Symbian coordinate system to VG coordinate system
+	vgLoadMatrix(Identity());
+		
+	// Add in translation for drawing engine coordinate system
+	vgTranslate(iOrigin.iX, iOrigin.iY);
+	}
+
+/**
+If aPath is a null handle, a VGPath is created with enough space to hold aExpectedCommandCount commands.
+If the path is already a handle to a valid path, the path is simply cleared instead of recreated.
+Also allocates memory for two arrays; one to hold all commands we will add to the newly
+created path, and one to hold all coordinates we will add to the newly created path.
+Commands and coordinates are not added to the path until FinishPath() is called for this path. 
+Commands and coordinates are saved for adding to the path when FinishPath() is
+called by calling AppendPathCommand(). Any failures are reported to the driver before returning.
+
+@param  aPath A handle to the path being cleared/created.
+@param	aExpectedCommandCount The number of commands the path is expected to hold. If this size
+		is underestimated, the arrays that hold the current commands and coordinates will grow
+		as additional items are added beyond the original estimated size. Once a path is finished, the current
+		command and coordinate counters are reset, but the memory remains to cut down on memory allocations.
+		
+@return EFalse if memory allocation or path creation fails, ETrue otherwise.
+
+@see CVgEngine::AppendPathCommand(VGubyte)
+@see CVgEngine::AppendPathCommand(VGubyte, VGfloat)
+@see CVgEngine::AppendPathCommand(VGubyte, VGfloat, VGfloat)
+@see CVgEngine::PrepareForPathCommand()
+@see CVgEngine::FinishPath()
+@see CVgEngine::AllocPathCommands()
+@see CVgEngine::AllocPathCoords()
+ */
+TBool CVgEngine::PreparePath(VGPath& aPath, TInt aExpectedCommandCount)
+	{	
+	TInt err = KErrNone;
+	err = AllocPathCommands(aExpectedCommandCount);		
+	if(KErrNone == err)
+		{
+		err = AllocPathCoords(aExpectedCommandCount*2);	// guess at the number of coords needed, this will be reallocated if it is not big enough
+		}
+	if(KErrNone == err)
+		{
+		if (aPath != VG_INVALID_HANDLE)
+			vgClearPath(aPath, VG_PATH_CAPABILITY_APPEND_TO);
+		else
+			{
+			aPath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
+							VG_PATH_DATATYPE_F,
+							1.0f, //scale
+							0.0f, //bias
+							aExpectedCommandCount,
+							aExpectedCommandCount*2, //expected coord count
+							VG_PATH_CAPABILITY_APPEND_TO);
+			
+			if (aPath == VG_INVALID_HANDLE)
+				err = KErrNoMemory;
+			}
+		}
+	if (KErrNone != err)
+		{
+		iDriver.SetError(err);
+		return EFalse;
+		}
+	return ETrue;
+	}
+
+/**
+Adds a path command to the currently saved array of path commands. Any error that occurs is stored
+with the driver.
+
+@param aCommand	The VGPathCommand to add to the current path, e.g VG_CLOSE_PATH.
+
+@see CVgEngine::CreatePath()
+@see CVgEngine::AppendPathCommand(VGubyte, VGfloat)
+@see CVgEngine::AppendPathCommand(VGubyte, VGfloat, VGfloat)
+@see CVgEngine::PrepareForPathCommand()
+@see CVgEngine::FinishPath()
+@see CVgEngine::AllocPathCommands()
+@see CVgEngine::AllocPathCoords()
+ */
+void CVgEngine::AppendPathCommand(VGubyte aCommand)
+	{
+	TInt err = PrepareForPathCommand(1, 0);
+	if (KErrNone == err)
+		{
+		iPathCommands[iPathCommandCount++] = aCommand;
+		}
+	else
+		{
+		iDriver.SetError(err);
+		}	
+	}
+
+/**
+Adds a path command and a single coordinate to the currently saved array of path commands.
+Any error that occurs is stored with the driver.  
+
+@param	aCommand The VGPathCommand to add to the current path, e.g VG_HLINE_TO_ABS.
+@param	aCoord	 The coordinate to add to the current path, e.g. 10.f.
+
+@see CVgEngine::CreatePath()
+@see CVgEngine::AppendPathCommand(VGubyte)
+@see CVgEngine::AppendPathCommand(VGubyte, VGfloat, VGfloat)
+@see CVgEngine::PrepareForPathCommand()
+@see CVgEngine::FinishPath()
+@see CVgEngine::AllocPathCommands()
+@see CVgEngine::AllocPathCoords()
+ */
+void CVgEngine::AppendPathCommand(VGubyte aCommand, VGfloat aCoord)
+	{
+	TInt err = PrepareForPathCommand(1, 1);
+	if (KErrNone == err)
+		{				
+		iPathCommands[iPathCommandCount++] = aCommand;			
+		iPathCoords[iPathCoordCount++] = aCoord;		
+		}
+	else
+		{
+		iDriver.SetError(err);
+		}	
+	}
+
+/**
+Adds a path command and two coordinates to the currently saved array of path commands. 
+Any error that occurs is stored with the driver.
+
+@param	aCommand	The VGPathCommand to add to the current path, e.g VG_MOVE_TO_ABS.
+@param	aCoord1		The coordinate to add to the current path, e.g. 10.f.
+@param	aCoord2		The coordinate to add to the current path, e.g. 10.f.
+
+@see CVgEngine::CreatePath()
+@see CVgEngine::AppendPathCommand(VGubyte)
+@see CVgEngine::AppendPathCommand(VGubyte, VGfloat)
+@see CVgEngine::PrepareForPathCommand()
+@see CVgEngine::FinishPath()
+@see CVgEngine::AllocPathCommands()
+@see CVgEngine::AllocPathCoords()
+ */
+void CVgEngine::AppendPathCommand(VGubyte aCommand, VGfloat aCoord1, VGfloat aCoord2)
+	{
+	TInt err = PrepareForPathCommand(1, 2);
+	if (KErrNone == err)
+		{			
+		iPathCommands[iPathCommandCount++] = aCommand;					
+		iPathCoords[iPathCoordCount++] = aCoord1;
+		iPathCoords[iPathCoordCount++] = aCoord2;		
+		}
+	else
+		{
+		iDriver.SetError(err);
+		}	
+	}
+
+/**
+Allocates memory to store the passed number of commands and coordinates in the saved command and 
+coordinate arrays. Any error that occurs is stored with the driver.
+
+@param	aCommandCount	The number of new commands expected to be added to the current command array.
+@param	aCoordCount		The number of new commands expected to be added to the current coordinate array.
+
+@return	KErrNoMemory if memory allocation fails, KErrNone otherwise.
+
+@see CVgEngine::CreatePath()
+@see CVgEngine::AppendPathCommand(VGubyte)
+@see CVgEngine::AppendPathCommand(VGubyte, VGfloat)
+@see CVgEngine::AppendPathCommand(VGubyte, VGfloat, VGfloat)
+@see CVgEngine::FinishPath()
+@see CVgEngine::AllocPathCommands()
+@see CVgEngine::AllocPathCoords()
+ */
+TInt CVgEngine::PrepareForPathCommand(TInt aCommandCount, TInt aCoordCount)
+	{
+	// Do we need to add space for the new commands and coords?
+	TInt err = AllocPathCommands(iPathCommandCount+aCommandCount);
+	if (err == KErrNone)
+		{
+		err = AllocPathCoords(iPathCoordCount+aCoordCount);
+		}
+	if (err != KErrNone)
+		{
+		iDriver.SetError(err);
+		}
+	return err;
+	}
+
+/**
+Adds the contents of the saved command and coordinate arrays to the passed VGPath ready for drawing.
+Clears the counts of saved commands and coordinates.
+
+@param	aPath	The path that the current commands and coordinates are to be added to. 
+
+@see CVgEngine::CreatePath()
+@see CVgEngine::AppendPathCommand(VGubyte)
+@see CVgEngine::AppendPathCommand(VGubyte, VGfloat)
+@see CVgEngine::AppendPathCommand(VGubyte, VGfloat, VGfloat)
+@see CVgEngine::PrepareForPathCommand()
+@see CVgEngine::AllocPathCommands()
+@see CVgEngine::AllocPathCoords()
+ */
+void CVgEngine::FinishPath(VGPath aPath)
+	{
+	vgAppendPathData(aPath, iPathCommandCount, iPathCommands, iPathCoords);
+	iPathCommandCount = 0;
+	iPathCoordCount = 0;
+	}
+
+/**
+Allocates enough memory to hold aCommandCount path commands, unless the command array already holds
+enough memory.
+
+@param	aCommandCount The number of commands to allocate space for in the command array.
+
+@return	KErrNoMemory if memory allocation fails, KErrNone otherwise.
+
+@see CVgEngine::CreatePath(TInt)
+@see CVgEngine::AppendPathCommand(VGubyte)
+@see CVgEngine::AppendPathCommand(VGubyte, VGfloat)
+@see CVgEngine::AppendPathCommand(VGubyte, VGfloat, VGfloat)
+@see CVgEngine::PrepareForPathCommand(TInt, TInt)
+@see CVgEngine::FinishPath(VGPath)
+@see CVgEngine::AllocPathCoords(TInt)
+ */
+TInt CVgEngine::AllocPathCommands(TInt aCommandCount)
+	{
+	TInt err = KErrNone;
+	if (iCurrentMaxCommands < aCommandCount)
+		{
+		VGubyte* oldPathCommands = iPathCommands;
+		iPathCommands = static_cast<VGubyte*>(User::ReAlloc(iPathCommands, sizeof(VGubyte)*aCommandCount));					
+		if (iPathCommands)
+			{
+			iCurrentMaxCommands = aCommandCount;	
+			}	
+		else
+			{
+			delete oldPathCommands;
+			iCurrentMaxCommands = 0;
+			}
+		}
+	if(!iPathCommands)
+		err = KErrNoMemory;
+	return err;	
+	}
+
+/**
+Allocates enough memory to hold aCoordCount path coordinates, unless the coordinate array already holds
+enough memory.
+
+@param	aCoordCount	The number of coordinates to allocate space for in the coordinate array.
+
+@return	KErrNoMemory if memory allocation fails, KErrNone otherwise.
+
+@see CVgEngine::CreatePath()
+@see CVgEngine::AppendPathCommand(VGubyte)
+@see CVgEngine::AppendPathCommand(VGubyte, VGfloat)
+@see CVgEngine::AppendPathCommand(VGubyte, VGfloat, VGfloat)
+@see CVgEngine::PrepareForPathCommand()
+@see CVgEngine::FinishPath()
+@see CVgEngine::AllocPathCommands()
+ */
+TInt CVgEngine::AllocPathCoords(TInt aCoordCount)
+	{
+	TInt err = KErrNone;
+	if (iCurrentMaxCoords < aCoordCount)
+		{
+		VGfloat* oldPathCoords = iPathCoords;
+		iPathCoords = static_cast<VGfloat*>(User::ReAlloc(iPathCoords, sizeof(VGfloat)*aCoordCount));			
+		if (iPathCoords)
+			{
+			iCurrentMaxCoords = aCoordCount;	
+			}	
+		else
+			{
+			delete oldPathCoords;
+			iCurrentMaxCoords = 0;
+			}
+		}
+	if(!iPathCoords)
+		err = KErrNoMemory;
+	return err;	
+	}
+
+/**
+Helper method for creating a VGImage from a CFbsBitmap. A temporary VGImageFormat-compatible 
+copy of the image may be created, if the source bitmap pixel format is not directly supported 
+by OpenVG. If there is not enough memory available, the error state on the driver is set to KErrNoMemory.
+It sets the error in the driver if out-of-memory occurs when creating a VGImage. OpenVG will set its 
+own internal error if creation of VGImage fails.
+
+@param	aSource	The source bitmap.
+@param  aFlipY If 'ETrue' then inverts the image in the y axis.
+@param  aOrigin An offset from the top-left of the image in which to take the first pixel of the image.
+
+@return	Returns a valid VGImage created using the passed CFbsBitmap. If unable to
+		create a valid VGImage then VG_INVALID_HANDLE.
+*/
+VGImage CVgEngine::CreateSourceVGImage(const CFbsBitmap& aSource, TBool aFlipY, const TPoint& aOrigin)
+	{		
+	TDisplayMode srcDisplayMode = aSource.DisplayMode();
+	TDisplayMode vgCompatibleDisplayMode = ClosestVgCompatibleDisplayMode(srcDisplayMode);
+	VGImageFormat imageFormat = MapToVgDisplayMode(vgCompatibleDisplayMode);
+	const TSize sourceSize = aSource.SizeInPixels();
+	VGImage image = DoVgCreateImage(imageFormat, sourceSize.iWidth, sourceSize.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED);
+	if (image != VG_INVALID_HANDLE)
+		{
+		const TInt pixmapStride = CFbsBitmap::ScanLineLength(sourceSize.iWidth, vgCompatibleDisplayMode);	
+		
+		// Conversion is performed if changing display mode (pixel format), source is compressed, or want to flip the y orientation.
+		if ((vgCompatibleDisplayMode != srcDisplayMode) || (aSource.Header().iCompression != ENoBitmapCompression) || aFlipY)
+			{
+			// May be worth using a static memory buffer for smaller scan-lines, to avoid overhead of alloc.
+			TAny* data = User::Alloc(pixmapStride);
+			if (data)
+				{
+				// Allocate memory and transform source into target format.
+				TPoint sourcePoint (0, aFlipY ? (sourceSize.iHeight - 1) : 0);
+				TPtr8 targetPoint ((TUint8*)data, pixmapStride, pixmapStride);
+				TInt adj = aFlipY ? -1 : 1;
+	
+				if (aOrigin == TPoint(0,0)) // Not shifted
+					{
+					for (TInt targetY = 0; targetY < sourceSize.iHeight; targetY++, sourcePoint.iY += adj)
+						{
+						aSource.GetScanLine(targetPoint, sourcePoint, sourceSize.iWidth, vgCompatibleDisplayMode);
+						vgImageSubData(image, data, pixmapStride, imageFormat, 0, targetY, sourceSize.iWidth, 1);
+						}
+					}
+				else if (aOrigin.iX == 0) // Only shifted in Y.
+					{
+					for (TInt targetY = 0x00; targetY < sourceSize.iHeight; targetY++, sourcePoint.iY += adj)
+						{
+						aSource.GetScanLine(targetPoint, sourcePoint, sourceSize.iWidth, vgCompatibleDisplayMode);
+						vgImageSubData(image, data, pixmapStride, imageFormat, 0, targetY + aOrigin.iY,                      sourceSize.iWidth, 1);
+						vgImageSubData(image, data, pixmapStride, imageFormat, 0, targetY + aOrigin.iY - sourceSize.iHeight, sourceSize.iWidth, 1);
+						}
+					}
+				else if (aOrigin.iY == 0) // Only shifted in X.
+					{
+					for (TInt targetY = 0x00; targetY < sourceSize.iHeight; targetY++, sourcePoint.iY += adj)
+						{
+						aSource.GetScanLine(targetPoint, sourcePoint, sourceSize.iWidth, vgCompatibleDisplayMode);
+						vgImageSubData(image, data, pixmapStride, imageFormat, -aOrigin.iX,                     targetY, sourceSize.iWidth, 1);
+						vgImageSubData(image, data, pixmapStride, imageFormat, -aOrigin.iX + sourceSize.iWidth, targetY, sourceSize.iWidth, 1);
+						}				
+					}
+				else						  // Shifted in both X and Y.
+					{
+					for (TInt targetY = 0; targetY < sourceSize.iHeight; targetY++, sourcePoint.iY += adj)
+						{
+						aSource.GetScanLine(targetPoint, sourcePoint, sourceSize.iWidth, vgCompatibleDisplayMode);
+						vgImageSubData(image, data, pixmapStride, imageFormat, -aOrigin.iX, 					targetY + aOrigin.iY, 						sourceSize.iWidth, 1);
+						vgImageSubData(image, data, pixmapStride, imageFormat, -aOrigin.iX, 					targetY + aOrigin.iY - sourceSize.iHeight, sourceSize.iWidth, 1);
+						vgImageSubData(image, data, pixmapStride, imageFormat, -aOrigin.iX + sourceSize.iWidth, targetY + aOrigin.iY, 						sourceSize.iWidth, 1);
+						vgImageSubData(image, data, pixmapStride, imageFormat, -aOrigin.iX + sourceSize.iWidth, targetY + aOrigin.iY - sourceSize.iHeight, sourceSize.iWidth, 1);
+						}
+					}
+				User::Free(data);
+				}
+			else
+				{
+				iDriver.SetError(KErrNoMemory);
+				vgDestroyImage(image);
+				return VG_INVALID_HANDLE;
+				}
+			}
+		else
+			{
+			aSource.BeginDataAccess();
+			const TInt sourceDataStride = aSource.DataStride();
+			if (aOrigin == TPoint(0,0))			// Not shifted
+				{
+				vgImageSubData(image, aSource.DataAddress(), sourceDataStride, imageFormat, 0, 0, sourceSize.iWidth, sourceSize.iHeight);			
+				}
+			else
+				{
+				TUint32* dataAddress = aSource.DataAddress();
+				
+				if (aOrigin.iX == 0) 		// Only shifted in Y.
+					{
+					vgImageSubData(image, dataAddress, sourceDataStride, imageFormat, 0, aOrigin.iY,                      sourceSize.iWidth, sourceSize.iHeight);						
+					vgImageSubData(image, dataAddress, sourceDataStride, imageFormat, 0, aOrigin.iY - sourceSize.iHeight, sourceSize.iWidth, sourceSize.iHeight);						
+					}
+				else if (aOrigin.iY == 0) 	// Only shifted in X.
+					{
+					vgImageSubData(image, dataAddress, sourceDataStride, imageFormat, -aOrigin.iX,                     0, sourceSize.iWidth, sourceSize.iHeight);						
+					vgImageSubData(image, dataAddress, sourceDataStride, imageFormat, -aOrigin.iX + sourceSize.iWidth, 0, sourceSize.iWidth, sourceSize.iHeight);						
+					}
+				else							// Shifted in both X and Y.
+					{
+					vgImageSubData(image, dataAddress, sourceDataStride, imageFormat, -aOrigin.iX, aOrigin.iY,                      sourceSize.iWidth, sourceSize.iHeight);						
+					vgImageSubData(image, dataAddress, sourceDataStride, imageFormat, -aOrigin.iX, aOrigin.iY - sourceSize.iHeight, sourceSize.iWidth, sourceSize.iHeight);							
+					vgImageSubData(image, dataAddress, sourceDataStride, imageFormat, -aOrigin.iX + sourceSize.iWidth, aOrigin.iY,                      sourceSize.iWidth, sourceSize.iHeight);						
+					vgImageSubData(image, dataAddress, sourceDataStride, imageFormat, -aOrigin.iX + sourceSize.iWidth, aOrigin.iY - sourceSize.iHeight, sourceSize.iWidth, sourceSize.iHeight);							
+					}
+				}
+			aSource.EndDataAccess(ETrue);
+			}
+		}
+	return image;
+	}
+
+/**
+Creates an image which represents a standard brush pattern (e.g. EVerticalHatchBrush), by
+drawing the pattern using the current pen and brush colour to an image.
+
+@param	aPatternSize	The dimensions in pixels of the image to create.
+@param	aBrushPattern	An array of 1s and 0s representing the pattern to create, the length
+						of this array is aSize.iWidth*aSize.iHeight.	
+
+@return	KErrNone if the brush is created successfully, KErrNoMemory if we fail to create 
+		the brush image, KErrArgument if aBrushPattern is invalid.
+ */
+TInt CVgEngine::CreateStandardBrush(TSize& aPatternSize, VGbyte* aBrushPattern)
+	{		
+	if (aBrushPattern == NULL)
+		return KErrArgument;
+	
+	TInt err = KErrNone;	
+	MakeEngineCurrent();
+	
+	// The image format to use as the standard brush. If this changes, it also needs changing in 
+	// GetCurrentBrush().	
+	const VGImageFormat dataFormat = VG_sARGB_8888;
+	
+	// We want to create the brush to the nearest power of 4 size.
+	TSize brushSize((aPatternSize.iWidth+3)&~3, (aPatternSize.iHeight+3)&~3);		
+	
+	// Allocate some memory to write the brush pattern to.
+	TUint32* data = new TUint32[brushSize.iWidth*brushSize.iHeight];
+	if (data == NULL)
+		err = KErrNoMemory;		
+	
+	if (err == KErrNone)
+		{
+		if (iBrushPatternStandardRegion != VG_INVALID_HANDLE)
+			{
+			vgDestroyImage(iBrushPatternStandardRegion);
+			iBrushPatternStandardRegion = VG_INVALID_HANDLE;
+			}
+		
+		// Check the size of the existing standard brush as it can't be re-used if the
+		// new brush to be created is a different size.
+		if (iBrushPatternStandard != VG_INVALID_HANDLE)
+			{
+			if (iBrushPatternStandardSize != brushSize)
+				{
+				vgDestroyImage(iBrushPatternStandard);
+				iBrushPatternStandard = VG_INVALID_HANDLE;
+				}
+			}					
+		
+		if (iBrushPatternStandard == VG_INVALID_HANDLE)
+			{
+			// Create an image to draw the brush pattern onto, this will be our offscreen buffer
+			iBrushPatternStandardSize = brushSize;
+			iBrushPatternStandard = DoVgCreateImage(dataFormat, brushSize.iWidth, brushSize.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED);
+			if (iBrushPatternStandard == VG_INVALID_HANDLE)
+				err = KErrNoMemory;
+			}
+		}			
+
+	if (err == KErrNone)
+		{
+		// Set the colour used for the pen. If not fully opaque and not in WriteAlpha mode,
+		// blend the pen colour with the brush colour.
+		TRgb penColor = iPenColor;
+		if ((iPenColor.Alpha() != 255) && (iDrawMode != DirectGdi::EDrawModeWriteAlpha))
+			{
+			penColor.SetInternal(
+				PMA2NonPMAPixel(
+					PMAPixelBlend(
+					    NonPMA2PMAPixel(iBrushColor.Internal()), 
+						NonPMA2PMAPixel(iPenColor.Internal()))));
+			}
+		
+		// Draw the pattern on to the brush, pixel by pixel.
+		for (TInt j = 0; j < aPatternSize.iHeight; ++j)
+			{
+			for (TInt i = 0; i < aPatternSize.iWidth; ++i)
+				{				
+				if (aBrushPattern[(j*aPatternSize.iWidth)+i])			
+					{					
+					data[(j*brushSize.iWidth)+i] = penColor._Color16MA(); 
+					}
+				else
+					{
+					data[(j*brushSize.iWidth)+i] = iBrushColor._Color16MA();
+					}
+				}
+			}					
+				
+		// Copy the pattern to the VGImage so we can set it as the current brush
+		vgImageSubData(iBrushPatternStandard,	// the image to copy to		
+					data, 						// the source data
+					brushSize.iWidth*4,	 		// the stride of the source data
+					dataFormat, 				// the format of the source data
+					0, 							// x
+					0, 							// y
+					brushSize.iWidth, 			// width
+					brushSize.iHeight);			// height
+		iBrushPatternStandardSize = brushSize;
+		
+		// We only want to use the region of the brush we just created that is the size of the pattern
+		iBrushPatternStandardRegion = vgChildImage(iBrushPatternStandard, 
+													0, 
+													0, 
+													aPatternSize.iWidth, 
+													aPatternSize.iHeight);
+		iBrushPatternStandardRegionSize = aPatternSize;
+		}		
+	
+	// Clean up
+	delete [] data;
+
+	return err;
+	}
+
+/**
+Internal function to return the currently active brush and its properties.
+@param aBrush On success, holds the current VGImage brush being used.
+@param aSize On success, holds the dimensions of VGImage being used as the brush.
+@param aFormat On success, holds the VGImageFormat of the brush. 
+@return ETrue if a brush is currently being used, EFalse otherwise.
+*/
+TBool CVgEngine::GetCurrentBrushPattern(VGImage& aBrush, TSize& aSize, VGImageFormat& aFormat) const
+	{
+	TBool success = ETrue;
+	if (iBrushStyle == DirectGdi::EPatternedBrush)
+		{
+		aBrush = iBrushPatternUser;
+		aSize = iBrushPatternUserSize;
+		aFormat = static_cast<VGImageFormat>(vgGetParameteri(aBrush, VG_IMAGE_FORMAT));
+		}
+	else if (iBrushStyle > DirectGdi::EPatternedBrush)
+		{
+		aBrush = iBrushPatternStandardRegion;
+		aSize = iBrushPatternStandardRegionSize;
+		// Currently we only ever use VG_sARGB_8888 for the standard brush format.
+		aFormat = VG_sARGB_8888;
+		}
+	else 
+		success = EFalse;
+	return success;
+	}
+
+/**
+Copies the current brush pattern (if a brush pattern is set) into iBrushPatternNonZeroOrigin.
+This function should only be used if the current brush origin is not (0,0). When copying the
+current brush pattern, it is shifted to take into account the non-zero origin. This shifted brush
+pattern should be used for all brush operations while a non-zero origin is set.
+
+@return	KErrNone if successful, KErrNotFound if the brush pattern could not be copied.
+ */
+TInt CVgEngine::CopyCurrentBrushPatternForNonZeroOrigin()
+	{
+	MakeEngineCurrent();
+	TInt ret = KErrNotFound;
+	VGImage brush = VG_INVALID_HANDLE;
+	TSize brushSize;
+	VGImageFormat imageFormat;
+	
+	if (GetCurrentBrushPattern(brush, brushSize, imageFormat))
+		{
+		const TInt width = brushSize.iWidth;
+		const TInt height = brushSize.iHeight;
+		
+		if ((width != 0) && (height != 0))
+			{
+			if (iBrushPatternNonZeroOrigin != VG_INVALID_HANDLE)
+				{
+				vgDestroyImage(iBrushPatternNonZeroOrigin);
+				iBrushPatternNonZeroOrigin = VG_INVALID_HANDLE;
+				}
+			
+			// Create the brush we are going to copy the current brush into
+			iBrushPatternNonZeroOrigin = DoVgCreateImage(imageFormat,
+													width,
+													height,
+													VG_IMAGE_QUALITY_FASTER);
+			if (iBrushPatternNonZeroOrigin != VG_INVALID_HANDLE)
+				{
+				TInt offsetX = width - (iBrushOrigin.iX % width);
+				TInt offsetY = height - (iBrushOrigin.iY % height);	
+				
+				// Top left to bottom right			
+				if (offsetX != 0 && offsetY != 0) // check the width and height we are copying are not 0
+					vgCopyImage(iBrushPatternNonZeroOrigin, width-offsetX, height-offsetY, brush, 0, 0, offsetX, offsetY, VG_FALSE);
+				
+				// Top right to bottom left
+				if ((width-offsetX) != 0 && offsetY != 0) 
+					vgCopyImage(iBrushPatternNonZeroOrigin, 0, height-offsetY, brush, offsetX, 0, width-offsetX, offsetY, VG_FALSE);
+				
+				// Bottom left to top right
+				if (offsetX != 0 && (height-offsetY) != 0) 
+					vgCopyImage(iBrushPatternNonZeroOrigin, width-offsetX, 0, brush, 0, offsetY, offsetX, height-offsetY, VG_FALSE);				
+				
+				// Bottom right to top left
+				if ((width-offsetX) != 0 && (height-offsetY) != 0) 
+					vgCopyImage(iBrushPatternNonZeroOrigin, 0, 0, brush, offsetX, offsetY, width-offsetX, height-offsetY, VG_FALSE);
+				
+				// Paint with the new non-zero origin brush
+				vgPaintPattern(iBrush, iBrushPatternNonZeroOrigin);
+				
+				ret = KErrNone;
+				}	
+			else
+				{
+				ret = KErrNoMemory;
+				}
+			}
+		}
+	
+	return ret;
+	}
+
+/**
+Calculates the angle in degrees formed anti-clockwise between vector V1 and V2, where V1 is a 
+horizontal vector to the right from aOriginX, and V2 is the vector (aPointX-aOriginX, aPointY-aOriginY).
+
+@param aOriginX	The x coordinate of a point which represents the origin of our calculation.
+@param aOriginY	The y coordinate of a point which represents the origin of our calculation.
+@param aPointX	The x coordinate of the point which defines the angle with the origin's x-axis.
+@param aPointY 	The y coordinate of the point which defines the angle with the origin's y-axis.
+@param aWidth	Width of the rectangle which defines where to draw the ellipse.
+@param aHeight 	Height of the rectangle which defines where to draw the ellipse.
+
+@panic DGDIAdapter 1006, if either width or height are less than 1 (debug-only).
+@return	The angle in degrees between the vectors V1 and V2 described above.
+ */
+TReal CVgEngine::GetAngleFromXAxisAnticlockwise(const TReal aOriginX, const TReal aOriginY, const TReal aPointX, const TReal aPointY, const TReal aWidth, const TReal aHeight)
+	{
+	GRAPHICS_ASSERT_DEBUG((aWidth > 0) && (aHeight > 0), EDirectGdiPanicInvalidParameter);
+
+// The angle is calculated from the radius line that joins the point to the origin.
+// The point initially provided defines a line relative to the ellipse.
+// But the VG spec states that the required angle is that for a perfect circle
+// before that circle is scaled by the bounding rect into an ellipse.
+// Therefore, downscale the position of the point relative to the origin, by the
+// relative dimensions of the width/height of the ellipse to make it relative to
+// the underlying circle. Then use the resulting circle radius line to calculate the angle.
+
+	TReal angle = 0.0f;		
+	TReal pointX = aPointX-aOriginX;
+	TReal pointY = aPointY-aOriginY;
+
+	const TReal scalingFactor = (aWidth / aHeight);
+	pointY *= scalingFactor;
+	Math::ATan(angle, pointY, pointX);
+	
+	// Adjust the angle for Q2 and Q3
+	if (pointY < 0)
+		angle = (KPi*2)+angle; 
+		
+	return angle*KRadToDeg;
+	}
+
+/**
+Method for drawing arcs or pies. An arc is a segment of an ellipse which is defined by a given rectangle. 
+The arc is drawn anti-clockwise from the arc start point to the arc end point. The arc start point is the 
+intersection between vectors from the centre of the ellipse to the given start position and the ellipse.
+The arc end point is defined in the same way.
+
+@param	aRect		The rectangle which defines where to draw the ellipse.
+@param	aStart		Position to be used in defining the arc start point.
+@param	aEnd		Position to be used in defining the arc end point.
+@param 	aArcType	The type of arc to draw; an arc, a chord or a pie.	
+
+@post	Request to draw an arc has been accepted. There is no guarantee that the request 
+		has been processed when the method returns.
+		
+@see	CVgEngine::DrawPie()
+@see	CVgEngine::DrawArc()
+ */
+void CVgEngine::DoDrawArc(const TRect& aRect, const TPoint& aStart, const TPoint& aEnd, VGUArcType aArcType)
+	{
+	MakeEngineCurrent();
+	
+	// Only draw if we are not painting with a NULL pen and a NULL brush
+	if (iPaintMode == 0)
+		return;
+		
+	// If the pen width and height are the same then draw as normal. If they are different but we should be filling
+	// this shape we need to draw the filled area only as normal (not the outline). The outline of the shape is drawn 
+	// in the block of code below to allow the effect of a different width and height pen to be applied.
+	if ((iPenSize.iWidth == iPenSize.iHeight) || ((iPaintMode & VG_FILL_PATH) && (aArcType == VGU_ARC_PIE)))
+		{
+		TReal originX = aRect.iTl.iX + (static_cast<TReal>(aRect.Width())*0.5);
+		TReal originY = aRect.iTl.iY + (static_cast<TReal>(aRect.Height())*0.5);
+		TReal startAngle = GetAngleFromXAxisAnticlockwise(originX, originY, aStart.iX, aStart.iY, aRect.Width(), aRect.Height());
+		TReal endAngle = GetAngleFromXAxisAnticlockwise(originX, originY, aEnd.iX, aEnd.iY, aRect.Width(), aRect.Height());		
+		TReal extent = endAngle - startAngle;
+		
+		// The extent defines what direction the arc is drawn in, so make sure we always draw
+		// anti-clockwise (-ve extent)
+		if (extent > 0.0f)
+			extent -= 360.0f;
+		
+		// If the start and end points are the same, make sure we draw arc all the way round the ellipse
+		if ((aStart == aEnd) || (extent > -0.0001f))
+			extent = -360.0f;
+		
+		// Before any vgu command, call SetError() as this stores the current vg error state (if any) in the 
+		// driver. Some implementations of vgu clears error state so we'd lose error codes otherwise.
+		iDriver.SetError(KErrNone);
+		
+		if (PreparePath(iVgPath, 5)) // N.B. 5 is just an initial hint as to how large the path may be, not its final size
+			{
+			VGUErrorCode err = vguArc(iVgPath, 
+				originX + 0.5f, 
+				originY + 0.5f, 
+				aRect.Width(), 
+				aRect.Height(), 
+				startAngle, 
+				extent, 
+				aArcType);
+			
+			if (err == VGU_NO_ERROR)
+				{
+				VGbitfield paintMode = iPaintMode;		
+				if(aArcType == VGU_ARC_OPEN)
+					{
+					paintMode &= ~VG_FILL_PATH;  
+					}
+				for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+					vgDrawPath(iVgPath, (iPenSize.iWidth == iPenSize.iHeight) ? paintMode : VG_FILL_PATH);				
+				}
+			else
+				{
+				SetVguError(err);
+				}
+			}
+		}
+	
+	if ((iPenSize.iWidth != iPenSize.iHeight)
+	&& (iPaintMode & VG_STROKE_PATH)		
+	&& (iPenSize.iWidth != 0) && (iPenSize.iHeight != 0))
+		{
+		// Setting a pen with different width and height is not available on OpenVG, so we need to scale 
+		// the coordinates we are drawing and apply a scaling matrix that scales by the width and height 
+		// of the pen to get the effect of a pen width different width and height.
+		TSize penSize = iPenSize;
+		SetPenSize(TSize(1, 1));
+		vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+		vgScale(penSize.iWidth, penSize.iHeight);			
+		VGfloat scaleX = 1.0f/(float)penSize.iWidth;
+		VGfloat scaleY = 1.0f/(float)penSize.iHeight;
+		
+		TReal originX = aRect.iTl.iX + (static_cast<TReal>(aRect.Width())*0.5);
+		TReal originY = aRect.iTl.iY + (static_cast<TReal>(aRect.Height())*0.5);
+		TReal startAngle = GetAngleFromXAxisAnticlockwise(originX, originY, aStart.iX, aStart.iY, aRect.Width(), aRect.Height());
+		TReal endAngle = GetAngleFromXAxisAnticlockwise(originX, originY, aEnd.iX, aEnd.iY, aRect.Width(), aRect.Height());		
+		TReal extent = endAngle - startAngle;
+		
+		// The extent defines what direction the arc is drawn in, so make sure we always draw
+		// anti-clockwise (-ve extent)
+		if (extent > 0.0f)
+			extent -= 360.0f;
+		
+		// If the start and end points are the same, make sure we draw arc all the way round the ellipse
+		if ((aStart == aEnd) || (extent > -0.0001f))
+			extent = -360.0f;
+		
+		// Before any vgu command, call SetError() as this stores the current vg error state (if any) in the 
+		// driver. Some implementations of vgu clears error state so we'd lose error codes otherwise.
+		iDriver.SetError(KErrNone);
+		
+		if (PreparePath(iVgPath, 5))
+			{
+			VGUErrorCode err = vguArc(iVgPath, 
+				(originX + 0.5f) * scaleX, 
+				(originY + 0.5f) * scaleY, 
+				(float)aRect.Width() * scaleX, 
+				(float)aRect.Height() * scaleY, 
+				startAngle, 
+				extent, 
+				aArcType);
+			
+			if (err == VGU_NO_ERROR)
+				{	
+				for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+					vgDrawPath(iVgPath, VG_STROKE_PATH);				
+				}
+			else
+				{
+				SetVguError(err);
+				}
+			}
+		
+		ResetVgMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
+		SetPenSize(penSize);
+		}
+	
+	}
+
+/**
+Helper function for drawing a source as a CDirectGdiImageSource.
+ 
+@see DrawResource(const TRect&, const RDirectGdiDrawableSource&, DirectGdi::TGraphicsRotation).
+ */
+void CVgEngine::DoDrawResource(const TRect& aDestRect,
+					CDirectGdiImageSourceImpl* aSource,
+					DirectGdi::TGraphicsRotation aRotation)
+
+	{
+	TSize size = aSource->Size();
+	TRect srcRect(0, 0, size.iWidth, size.iHeight);
+	
+	DoDrawResource(aDestRect, aSource, srcRect, aRotation);
+	}
+
+/**
+Helper function for drawing a source as a CDirectGdiImageSource. 
+
+@see DrawResource(const TRect&, const RDirectGdiDrawableSource&, const TRect&, DirectGdi::TGraphicsRotation). 
+ */
+void CVgEngine::DoDrawResource(const TRect& aDestRect,
+					CDirectGdiImageSourceImpl* aSource,
+					const TRect& aSourceRect,
+					DirectGdi::TGraphicsRotation aRotation)
+	{				 
+	// If the source rect is smaller than the actual source size then we need to create a child VGImage to draw
+	VGImage vgImage = aSource->VgImage();
+	TSize size = aSource->Size();
+	if ((aSourceRect.Width() < size.iWidth) || (aSourceRect.Height() < size.iHeight))
+		{
+		vgImage = vgChildImage(vgImage, aSourceRect.iTl.iX, aSourceRect.iTl.iY, aSourceRect.Width(), aSourceRect.Height());
+		}
+		
+	if (vgImage != VG_INVALID_HANDLE)
+		{
+		vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);	
+		
+		TRect destRect(aDestRect);
+		TRect sourceRect(aSourceRect);
+
+		if (aRotation == DirectGdi::EGraphicsRotationNone ||
+			aRotation == DirectGdi::EGraphicsRotation180)
+			{
+			// Pixel-data in EGLImages appears to be upside down due to the Y-inversion 
+			// effect of the Identity matrix.  Therefore must undo the Y-inversion here 
+			// and adjust destination rect accordingly.			
+			const TInt destRectHeight = aDestRect.Height();
+			destRect.iTl.iY = (iSize.iHeight - aDestRect.iTl.iY - iOrigin.iY) - destRectHeight;
+			destRect.iTl.iX += iOrigin.iX;
+			destRect.iBr.iX += iOrigin.iX;
+			destRect.iBr.iY = destRect.iTl.iY + destRectHeight;
+			sourceRect.iBr.iY = aSource->Size().iHeight - sourceRect.iTl.iY;
+			sourceRect.iTl.iY = sourceRect.iBr.iY - aSourceRect.Height();
+			vgLoadIdentity();
+			}
+		else
+			{
+			// But if rotation is 90 or 270 degrees, only need to mirror in the X-axis.
+			vgScale(-1, 1);
+			}
+
+		VGfloat xScale = 1.f;
+		VGfloat yScale = 1.f;				
+		VGint posX = destRect.iTl.iX;
+		VGint posY = destRect.iTl.iY;		
+					
+		switch (aRotation)
+			{									
+			case DirectGdi::EGraphicsRotation90:
+				xScale = ((VGfloat)destRect.Width()/(VGfloat)sourceRect.Height());
+				yScale = ((VGfloat)destRect.Height()/(VGfloat)sourceRect.Width());																	
+				vgTranslate(-posX, posY);
+				vgScale(xScale, yScale);
+				vgRotate(90.0f);					
+				break;
+			case DirectGdi::EGraphicsRotation180:								
+				xScale = ((VGfloat)destRect.Width()/(VGfloat)sourceRect.Width());
+				yScale = ((VGfloat)destRect.Height()/(VGfloat)sourceRect.Height());
+				vgTranslate(posX+destRect.Width(), posY+destRect.Height());
+				vgScale(xScale, yScale);
+				vgRotate(180.0f);												
+				break;
+			case DirectGdi::EGraphicsRotation270:
+				xScale = ((VGfloat)destRect.Width()/(VGfloat)sourceRect.Height());
+				yScale = ((VGfloat)destRect.Height()/(VGfloat)sourceRect.Width());
+				vgTranslate(-posX-destRect.Width(), (posY+destRect.Height()));
+				vgScale(xScale, yScale);
+				vgRotate(270.0f);
+				break;
+			default: // DirectGdi::EGraphicsRotationNone
+				xScale = ((VGfloat)destRect.Width()/(VGfloat)sourceRect.Width());
+				yScale = ((VGfloat)destRect.Height()/(VGfloat)sourceRect.Height());
+				vgTranslate(posX, posY);
+				vgScale(xScale, yScale);
+				break;
+			}																							
+		
+		for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
+			vgDrawImage(vgImage);
+		
+		if (vgImage != aSource->VgImage())
+			{
+			// Created a child VGImage, so destroy after use.
+			vgDestroyImage(vgImage);
+			}
+		
+		ResetVgMatrix(VG_MATRIX_IMAGE_USER_TO_SURFACE);
+		}
+	}
+
+/**
+Maps a VGU error code to a Symbian OS error code, and sets the driver's error state. If the 
+error is unrecognised, the error is set to KErrGeneral.
+
+@param aErr The return value (error state) from a VGU command.
+@post If empty, the driver's error state is updated to the mapped error code.
+*/
+void CVgEngine::SetVguError(VGUErrorCode aErr)
+	{
+	switch(aErr)
+		{
+		case VGU_NO_ERROR:
+			break;
+		case VGU_OUT_OF_MEMORY_ERROR:
+			iDriver.SetError(KErrNoMemory);
+			break;
+		case VGU_BAD_HANDLE_ERROR:
+			iDriver.SetError(KErrBadHandle);
+			break;
+		case VGU_ILLEGAL_ARGUMENT_ERROR:
+			iDriver.SetError(KErrArgument);
+			break;
+		case VGU_PATH_CAPABILITY_ERROR:
+			iDriver.SetError(KErrNotSupported);
+			break;
+		default:
+			iDriver.SetError(KErrGeneral);
+			break;
+		}
+	}	
+
+/**
+Helper method for creating a VGImage. This method clears the VG image cache in an attempt to  
+reclaim some memory if creation of a VGImage fails due to no memory being available, 
+it then tries to create the image again. If image creation fails again it then clears the glyph 
+cache and tries to create the image again. If image creation still fails, OpenVG is forced to 
+complete all currently outstanding drawing requests, so that any OpenVG objects marked for deletion,
+such as VGImages that are currently waiting to be drawn, are freed. This is an attempt to make sure 
+that images are still displayed in low memory conditions. Use this method instead of calling 
+vgCreateImage() directly. Clearing the VG image cache in this way will have a negative effect on 
+performance regarding speed, but it is more important that an attempt is made to draw something 
+when memory is low.
+
+@param aFormat The pixel format of the image to be created
+@param aWidth The width of the image to be created
+@param aHeight The height of the image to be created
+@param aAllowedQuality One of the VGImageQuality flags
+
+@return A VGImage handle if the image was created successfully, VG_INVALID_HANDLE otherwise 
+ */
+VGImage CVgEngine::DoVgCreateImage(VGImageFormat aFormat, VGint aWidth, VGint aHeight, VGbitfield aAllowedQuality)
+	{
+	const TInt oldVgError = CDirectGdiDriverImpl::GetVgError();
+	VGImage imageRet = vgCreateImage(aFormat, aWidth, aHeight, aAllowedQuality);
+	
+	if (imageRet == VG_INVALID_HANDLE)
+		{
+		// If the new error is anything other than KErrNoMemory, there is nothing that can be done.
+		TInt newVgError = CDirectGdiDriverImpl::GetVgError();		
+		if (newVgError != KErrNoMemory)
+			{
+			iDriver.SetError(oldVgError != KErrNone ? oldVgError : newVgError);
+			return imageRet;
+			}
+
+		// From here on, we are assuming any failure to create the image is due to OOM.
+		if (iDriver.VgImageCache())
+			{
+			// Delete all the images that are currently in the cache then try and create the image again
+			iDriver.VgImageCache()->ResetCache();
+			imageRet = vgCreateImage(aFormat, aWidth, aHeight, aAllowedQuality);
+			}
+		if ((imageRet == VG_INVALID_HANDLE) && iFontGlyphImageStorage)
+			{
+			// Clear the glyph cache as well then try and create the image again
+			iFontGlyphImageStorage->CleanGlyphImageCache();
+			imageRet = vgCreateImage(aFormat, aWidth, aHeight, aAllowedQuality);
+			}
+		if ((imageRet == VG_INVALID_HANDLE))
+			{
+			// Finally, force completion of any outstanding drawing, may free any VGImages marked for deletion.
+			// Empty the current OpenVG error state before calling Finish(), as Finish() may call SetError(),
+			// and could prematurely set the driver error state to KErrNoMemory.
+			//coverity[check_return]
+			//coverity[unchecked_value]
+			vgGetError();
+			iDriver.Finish();
+			imageRet = vgCreateImage(aFormat, aWidth, aHeight, aAllowedQuality);
+			}
+
+		// If the above worked, empty any OpenVG error state set by any failed attempts to create the image.
+		if (imageRet != VG_INVALID_HANDLE)
+			{
+			//coverity[check_return]
+			//coverity[unchecked_value]
+			vgGetError();
+			}
+		}
+	
+	// Reset the error code to the original VG error code. If oldVgError is KErrNone, 
+	// SetError() will use the current OpenVG error state.
+	iDriver.SetError(oldVgError);
+	
+	return imageRet;
+	}
+
+/**
+Helper method for setting the colour property of a VGPaint object from a TRgb structure.
+
+@param aPaint The VGPaint object to change the colour property of.
+@param aColor The colour to set the paint to.
+*/ 
+void CVgEngine::SetVgPaintColor(VGPaint& aPaint, const TRgb& aColor)
+	{
+	// Need to swap from internal ARGB to RGBA for OpenVG.
+	const TUint argb = aColor.Internal();
+	const VGuint rgba = ((argb & 0xFFFFFF) << 8) + ((argb & 0xFF000000) >> 24);
+	vgSetColor(aPaint, rgba);
+	}