windowing/windowserver/tdynamicres/src/surfaceutility.cpp
changeset 0 5d03bc08d59c
child 36 01a6848ebfd7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/tdynamicres/src/surfaceutility.cpp	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,1544 @@
+// 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:
+//
+
+/**
+ @file
+*/
+
+#include <e32std.h>
+#include <imageconversion.h>
+#include "surfaceutility.h"
+
+CSurfaceUtility::CSurfaceUtility(CSurfaceUtility* aClone/*=NULL*/)
+	:	iSurfaces(aClone?&(aClone->iSurfaces):NULL)
+	{
+	}
+	
+CSurfaceUtility* CSurfaceUtility::NewL(CSurfaceUtility* aClone/*=NULL*/)
+	{
+	CSurfaceUtility* utility = new (ELeave)CSurfaceUtility(aClone);
+	CleanupStack::PushL(utility);
+	utility->ConstructL();
+	CleanupStack::Pop(utility);
+	return utility;
+	}
+	
+void CSurfaceUtility::ConstructL()
+	{
+	TInt r = iManager.Open();
+	if (r != KErrNone)
+		{
+		LOG(("Surface manager failed to open: %d", r));
+		User::Leave(r);
+		}
+	
+	r = iSurfaceUpdateSession.Connect();
+	if (r != KErrNone)
+		{
+		LOG(("Failed to connect to update server: %d", r));
+		User::Leave(r);
+		}
+	}
+	
+CSurfaceUtility::~CSurfaceUtility()
+	{
+	DestroyAll();
+
+	iSurfaces.Close();
+
+	iManager.Close();
+
+	iSurfaceUpdateSession.Close();
+	}
+
+TBool CSurfaceUtility::DestroyAll()
+	{
+	TInt err = 	KErrNone;
+	TInt jj = iSurfaces.Count() - 1;
+	if (jj<0)
+		return EFalse;
+	for (; jj >= 0; jj--)
+		{
+		err = iManager.CloseSurface(iSurfaces[jj]);
+		if (err!=KErrNone)
+			{
+			LOG(("Error closing surface: 0x%X\n", err));
+			}
+		}
+	iSurfaces.Reset();
+	return ETrue;
+	}
+
+/***************************************
+ * The aim of the THeapSurfaceArray is to locally switch in the specified heap for any array operation
+ ***************************************/
+
+CSurfaceUtility::RHeapSurfaceArray::RHeapSurfaceArray(RHeapSurfaceArray* aUseExternalArray)
+	:	iUseArray(aUseExternalArray?aUseExternalArray->iUseArray:&this->iLocalArray),
+	iExternalHeapRef(aUseExternalArray?aUseExternalArray->iExternalHeapRef:User::Heap())
+	{
+	
+	}
+/************************************
+ * The following methods have been used by the surfaceutility... some require the heap wrapping, and some don't
+ * I actually need three different startegies (count em) for 7 methods...
+ * Some methods only read the existing objects, so don't need a heap swap at all
+ * Leaving methods have to use PopAndDestroy strategy to restore the heap on leaving or success
+ * Non-leaving methods must not call PushL, so directly make SwitchHeap calls!
+ ************************************/
+
+// PopAndDestroy method to restore the heap
+/*static*/ void	CSurfaceUtility::RHeapSurfaceArray::PopHeap(void* aHeapPtr)
+	{
+	RHeap* heapPtr=(RHeap*)aHeapPtr;
+	User::SwitchHeap(heapPtr);
+	}
+
+// Switches and pushes the previous heap so it can be restored with PopAndDestroy
+/*static*/ void CSurfaceUtility::RHeapSurfaceArray::SwitchHeapLC(RHeap* aNewHeap)
+	{
+	CleanupStack::PushL(TCleanupItem(PopHeap,NULL));
+	CleanupStack::PushL(TCleanupItem(PopHeap,NULL));
+	CleanupStack::PushL(TCleanupItem(PopHeap,NULL));
+	CleanupStack::Pop(3);
+	RHeap* oldHeap=User::SwitchHeap(aNewHeap);
+	delete new char;
+	CleanupStack::PushL(TCleanupItem(PopHeap,oldHeap));
+	}
+
+
+TSurfaceId& CSurfaceUtility::RHeapSurfaceArray::operator[](TUint aIndex)
+	{
+	return iUseArray->operator[](aIndex);
+	}
+// Close only closes the local array, while Reset resets the active array (may be external)
+void CSurfaceUtility::RHeapSurfaceArray::Close()
+	{
+	RHeap* oldHeap=User::SwitchHeap(&iExternalHeapRef);
+	iLocalArray.Close();
+	User::SwitchHeap(oldHeap);
+	}
+TInt CSurfaceUtility::RHeapSurfaceArray::Count() const
+	{
+	return iUseArray->Count();
+	}
+// Close only closes the local array, while Reset resets the active array (may be external)
+inline void CSurfaceUtility::RHeapSurfaceArray::Reset()
+	{
+	RHeap* oldHeap=User::SwitchHeap(&iExternalHeapRef);
+	iUseArray->Reset();
+	User::SwitchHeap(oldHeap);
+	}
+void CSurfaceUtility::RHeapSurfaceArray::AppendL(const TSurfaceId &anEntry)
+	{
+	SwitchHeapLC(&iExternalHeapRef);
+	iUseArray->AppendL(anEntry);
+	CleanupStack::PopAndDestroy();
+	}
+TInt CSurfaceUtility::RHeapSurfaceArray::Find(const TSurfaceId &anEntry) const
+	{
+	return iUseArray->Find(anEntry);
+	}
+void CSurfaceUtility::RHeapSurfaceArray::Remove(TInt anIndex)
+	{
+	RHeap* oldHeap=User::SwitchHeap(&iExternalHeapRef);
+	iUseArray->Remove(anIndex);
+	User::SwitchHeap(oldHeap);
+	}
+
+
+
+
+/**
+Cleanup stack helper object, holding references to both utility and surface, so
+that the standard Close() semantics can be used.
+*/
+class TSurfaceCleanup
+	{
+public:
+	TSurfaceCleanup(CSurfaceUtility& aUtility, TSurfaceId& aSurface)
+		: iUtility(aUtility), iSurface(aSurface)
+		{}
+	void Close()
+		{
+		// Removes the surface from the list of surfaces to clean up, and closes
+		// the surface reference.
+		iUtility.DestroySurface(iSurface);
+		}
+private:
+	CSurfaceUtility& iUtility;
+	TSurfaceId& iSurface;
+	};
+
+/**
+Read the given image file into a new surface.
+
+@param aFileName The name of the image file.
+@param aSurface Filled with the surface ID for the surface containing the pixels.
+*/
+void CSurfaceUtility::CreateSurfaceFromFileL(const TDesC& aFileName, TSurfaceId& aSurface)
+	{
+	RFs fs;
+	
+	User::LeaveIfError(fs.Connect());
+	CleanupClosePushL(fs);
+	CImageDecoder* decoder = CImageDecoder::FileNewL(fs, aFileName, CImageDecoder::EOptionAlwaysThread);
+	CleanupStack::PushL(decoder);
+
+	const TFrameInfo& info = decoder->FrameInfo();
+
+	TSize size = info.iOverallSizeInPixels;
+	TInt stride = size.iWidth << 2;		// Default to four bytes per pixel
+	TDisplayMode bmpFormat = info.iFrameDisplayMode;
+	TUidPixelFormat pixelFormat = EUidPixelFormatUnknown;
+
+	switch (bmpFormat)
+		{
+		case EGray2:
+		case EGray4:
+		case EGray16:
+		case EGray256:
+		case EColor16:
+		case EColor256:
+		case EColor16M:
+		case EColor16MU:
+			{
+			bmpFormat = EColor16MU;
+			pixelFormat = EUidPixelFormatXRGB_8888;
+			break;
+			}
+		case EColor4K:
+			{
+			stride = size.iWidth << 1;
+			pixelFormat = EUidPixelFormatXRGB_4444;
+			break;
+			}
+		case EColor64K:
+			{
+			stride = size.iWidth << 1;
+			pixelFormat = EUidPixelFormatRGB_565;
+			break;
+			}
+		case EColor16MA:
+			{
+			pixelFormat = EUidPixelFormatARGB_8888;
+			break;
+			}
+		case EColor16MAP:
+			{
+			pixelFormat = EUidPixelFormatARGB_8888_PRE;
+			break;
+			}
+		default:
+			{
+			LOG(("Unsupported display mode: %d", bmpFormat));
+			User::Leave(KErrNotSupported);
+			break;
+			}
+		}
+
+	// Create an intermediary bitmap for decoding into
+	CFbsBitmap* bitmap = new (ELeave) CFbsBitmap();
+	CleanupStack::PushL(bitmap);
+	User::LeaveIfError(bitmap->Create(size, info.iFrameDisplayMode));
+
+	// Create the final surface.
+	aSurface = CreateSurfaceL(size, pixelFormat, stride);
+	TSurfaceCleanup surfaceCleanup(*this, aSurface);
+	CleanupClosePushL(surfaceCleanup);
+
+	RChunk chunk;
+	User::LeaveIfError(iManager.MapSurface(aSurface, chunk));
+	CleanupClosePushL(chunk);
+
+	// Convert the image file into a Symbian bitmap
+	TRequestStatus status;
+	decoder->Convert(&status, *bitmap);
+	User::WaitForRequest(status);
+	User::LeaveIfError(status.Int());
+
+	TInt offsetToFirstBuffer;
+	User::LeaveIfError(iManager.GetBufferOffset(aSurface, 0, offsetToFirstBuffer));
+	
+	// Copy the data from the bitmap into the surface.
+	TPoint start;
+	TUint8 *pSurfStart = chunk.Base() + offsetToFirstBuffer; 
+	for (start.iY = 0; start.iY < size.iHeight; start.iY++)
+		{
+		// Set up a descriptor for the current line in the surface and get pixels.
+		TPtr8 ptr(pSurfStart + start.iY * stride, stride);
+		bitmap->GetScanLine(ptr, start, size.iWidth, bmpFormat);
+		}
+
+	CleanupStack::PopAndDestroy(/* chunk */);
+	CleanupStack::Pop(/* surfaceCleanup */);
+	CleanupStack::PopAndDestroy(bitmap);
+	CleanupStack::PopAndDestroy(decoder);
+	CleanupStack::PopAndDestroy(/* fs */);
+	}
+
+void CSurfaceUtility::CopyBitmapSurfaceL(const CFbsBitmap* aBitmap, TSurfaceId& aSurface)
+	{
+	RChunk chunk;
+	User::LeaveIfError(iManager.MapSurface(aSurface, chunk));
+	CleanupClosePushL(chunk);
+	TSize bitmapSize = aBitmap->SizeInPixels();
+	TSize size = SurfaceSize(aSurface);
+	TInt stride = size.iWidth*4;		// Default to four bytes per pixel
+
+	TInt offsetToFirstBuffer;
+	User::LeaveIfError(iManager.GetBufferOffset(aSurface, 0, offsetToFirstBuffer));
+	
+	// Copy the data from the bitmap into the surface.
+	TPoint start;
+	TUint8 *pSurfStart = chunk.Base() + offsetToFirstBuffer; 
+	for (start.iY = 0; start.iY < bitmapSize.iHeight; start.iY++)
+		{
+		// Set up a descriptor for the current line in the surface and get pixels.
+		TPtr8 ptr(pSurfStart + start.iY * stride, stride);
+		aBitmap->GetScanLine(ptr, start, bitmapSize.iWidth, EColor16MU);
+		}
+	CleanupStack::PopAndDestroy(/* chunk */);
+
+	}
+/**
+Copy the bitmap from a file to a surface.
+
+@param aFileName The name of the image file.
+@param aSurface Filled with the surface ID for the surface containing the pixels.
+*/
+void CSurfaceUtility::CopyBitmapFromFileToSurfaceL(const TDesC& aFileName, TSurfaceId& aSurface)
+	{
+	RFs fs;
+	
+	User::LeaveIfError(fs.Connect());
+	CleanupClosePushL(fs);
+	CImageDecoder* decoder = CImageDecoder::FileNewL(fs, aFileName, CImageDecoder::EOptionAlwaysThread);
+	CleanupStack::PushL(decoder);
+
+	const TFrameInfo& info = decoder->FrameInfo();
+
+	RSurfaceManager::TInfoBuf infoBuf;
+	RSurfaceManager::TSurfaceInfoV01& infoSurf = infoBuf();
+	User::LeaveIfError(iManager.SurfaceInfo(aSurface, infoBuf));
+	
+	TSize size = infoSurf.iSize;
+	TDisplayMode bmpFormat = info.iFrameDisplayMode;
+	TInt stride = size.iWidth << 2;		// Default to four bytes per pixel
+
+	// Create an intermediary bitmap for decoding into
+	CFbsBitmap* bitmap = new (ELeave) CFbsBitmap();
+	CleanupStack::PushL(bitmap);
+	User::LeaveIfError(bitmap->Create(size, info.iFrameDisplayMode));
+
+	RChunk chunk;
+	User::LeaveIfError(iManager.MapSurface(aSurface, chunk));
+	CleanupClosePushL(chunk);
+
+	// Convert the image file into a Symbian bitmap
+	TRequestStatus status;
+	decoder->Convert(&status, *bitmap);
+	User::WaitForRequest(status);
+	User::LeaveIfError(status.Int());
+
+	TInt offsetToFirstBuffer;
+	User::LeaveIfError(iManager.GetBufferOffset(aSurface, 0, offsetToFirstBuffer));
+
+	// Copy the data from the bitmap into the surface.
+	TPoint start;
+	TUint8 *pSurfStart = chunk.Base() + offsetToFirstBuffer;
+	for (start.iY = 0; start.iY < size.iHeight; start.iY++)
+		{
+		// Set up a descriptor for the current line in the surface and get pixels.
+		TPtr8 ptr(pSurfStart + start.iY * stride, stride);
+		bitmap->GetScanLine(ptr, start, size.iWidth, bmpFormat);
+		}
+
+	CleanupStack::PopAndDestroy(/* chunk */);
+	CleanupStack::PopAndDestroy(bitmap);
+	CleanupStack::PopAndDestroy(decoder);
+	CleanupStack::PopAndDestroy(/* fs */);
+	}
+/**
+Get the size of a surface.
+
+@param aSurface The surface to get the size for.
+@return The size in pixels, or empty on failure.
+*/
+TSize CSurfaceUtility::SurfaceSize(const TSurfaceId& aSurface)
+	{
+	RSurfaceManager::TInfoBuf infoBuf;
+	RSurfaceManager::TSurfaceInfoV01& info = infoBuf();
+
+	if (iManager.SurfaceInfo(aSurface, infoBuf) == KErrNone)
+		{
+		return info.iSize;
+		}
+
+	return TSize();
+	}
+
+
+/**
+Create a surface using the surface manager.
+
+Stores the ID for tear down, as well as returning it.
+
+@param aSize Dimensions of the surface.
+@param aPixelFormat	UID of the pixel format.
+@param aStride	Stride value for the surface (usually bytes per pixel * width)
+@leave May leave due to lack of memory.
+@return New surface's ID.
+*/
+TSurfaceId CSurfaceUtility::CreateSurfaceL(const TSize& aSize, TUidPixelFormat aPixelFormat, TInt aStride, TInt aBuffers)
+	{
+	RSurfaceManager::TSurfaceCreationAttributesBuf bf;
+	RSurfaceManager::TSurfaceCreationAttributes& b = bf();
+	
+	b.iSize.iWidth = aSize.iWidth;
+	b.iSize.iHeight = aSize.iHeight;
+	b.iBuffers = aBuffers;				// number of buffers in the surface
+	b.iPixelFormat = aPixelFormat;
+	b.iStride = aStride;		// Number of bytes between start of one line and start of next
+	b.iOffsetToFirstBuffer = 0;	// way of reserving space before the surface pixel data
+	b.iAlignment = 4;			// alignment, 1,2,4,8 byte aligned
+	b.iContiguous = EFalse;
+	b.iMappable = ETrue;
+
+	TSurfaceId surface = TSurfaceId::CreateNullId();
+
+	User::LeaveIfError(iManager.CreateSurface(bf, surface));
+	iSurfaces.AppendL(surface);
+	return surface;
+	}
+
+/**
+A helper function that returns the bytes per pixel for a given pixel format uid
+
+@param aPixelFormat Pixel format UID to convert
+@return The bytes per pixel
+*/
+TInt CSurfaceUtility::BytesPerPixelL(TUidPixelFormat aPixelFormat)
+	{
+	TInt bytesPerPixel = 0;
+	switch (aPixelFormat)
+		{
+		case EUidPixelFormatXRGB_8888:
+		case EUidPixelFormatARGB_8888:
+		case EUidPixelFormatARGB_8888_PRE:
+			{
+			bytesPerPixel = 4;
+			break;
+			}
+		case EUidPixelFormatXRGB_4444:
+		case EUidPixelFormatARGB_4444:
+		case EUidPixelFormatRGB_565:
+			{
+			bytesPerPixel = 2;
+			break;
+			}
+		default:
+			{
+			User::Leave(KErrNotSupported);
+			break;
+			}
+		}
+	return bytesPerPixel;
+	}
+
+/**
+Fill the given surface with a color.
+
+@param aSurface	The surface to be filled.
+@param aColor	The color to fill it with.
+*/
+void CSurfaceUtility::FillSurfaceL(TSurfaceId& aSurface, const TRgb& aColor)
+	{
+	RSurfaceManager::TInfoBuf infoBuf;
+	RSurfaceManager::TSurfaceInfoV01& info = infoBuf();
+
+	User::LeaveIfError(iManager.SurfaceInfo(aSurface, infoBuf));
+	TUint32 color = 0;
+	TBool use16 = EFalse;
+
+	if (info.iSize.iHeight<0 || info.iSize.iWidth<0 || info.iStride<0)
+		{
+		User::Leave(KErrCorrupt);
+		}
+	if (info.iSize.iHeight==0 || info.iSize.iWidth==0 || info.iStride==0)
+		{
+		User::Leave(KErrNotReady);
+		}
+
+	switch (info.iPixelFormat)
+		{
+		case EUidPixelFormatXRGB_8888:
+			{
+			color = aColor.Color16MU();
+#ifdef ALPHA_FIX_24BIT
+			color |= ((ALPHA_FIX_24BIT)&0xff)<<24;
+#endif
+			break;
+			}
+		case EUidPixelFormatARGB_8888:
+			{
+			color = aColor.Color16MA();
+			break;
+			}
+		case EUidPixelFormatARGB_8888_PRE:
+			{
+			color = aColor.Color16MAP();
+			break;
+			}
+		case EUidPixelFormatXRGB_4444:
+		case EUidPixelFormatARGB_4444:
+			{
+			color = aColor.Color4K();
+			use16 = ETrue;
+			break;
+			}
+		case EUidPixelFormatRGB_565:
+			{
+			color = aColor.Color64K();
+			use16 = ETrue;
+			break;
+			}
+		default:
+			{
+			User::Leave(KErrNotSupported);
+			break;
+			}
+		}
+
+	RChunk chunk;
+	User::LeaveIfError(iManager.MapSurface(aSurface, chunk));
+	CleanupClosePushL(chunk);
+
+	TInt offsetToFirstBuffer;
+	User::LeaveIfError(iManager.GetBufferOffset(aSurface, 0, offsetToFirstBuffer));
+	TUint8* surfacePtr = chunk.Base() + offsetToFirstBuffer;
+	TUint8* linePtr = surfacePtr;
+
+	if (use16)
+		{
+		if ( info.iSize.iWidth*2>info.iStride)
+			{
+			User::Leave(KErrOverflow);
+			}
+		TUint16* ptr = reinterpret_cast<TUint16*>(surfacePtr);
+
+		// Fill first line
+		for (TInt xx = 0; xx < info.iSize.iWidth; xx++)
+			{
+			ptr[xx] = (TUint16)color;
+			}
+		}
+	else
+		{
+		if ( info.iSize.iWidth*4>info.iStride)
+			{
+			User::Leave(KErrOverflow);
+			}
+		TUint32* ptr = reinterpret_cast<TUint32*>(surfacePtr);
+
+		// Fill first line
+		for (TInt xx = 0; xx < info.iSize.iWidth; xx++)
+			{
+			ptr[xx] = color;
+			}
+		}
+
+	// Now copy that to the other lines
+	for (TInt yy = 1; yy < info.iSize.iHeight; yy++)
+		{
+		linePtr += info.iStride;
+		Mem::Copy(linePtr, surfacePtr, info.iSize.iWidth * BytesPerPixelL(info.iPixelFormat));
+		}
+	
+	TInt err = iSurfaceUpdateSession.SubmitUpdate(0, aSurface, 0, NULL);
+	if (err!=KErrNone)
+		LOG(("Error submitting update: 0x%X\n", err));
+
+	CleanupStack::PopAndDestroy(/* chunk */);
+	}
+
+/**
+Fill the given memory chunk with a color.
+
+@param aSurface	The surface to be filled.
+@param aChunk	The surface to be filled.
+@param aColor	The color to fill it with.
+*/
+void CSurfaceUtility::FillChunkL(TSurfaceId& aSurface, RChunk& aChunk, const TRgb& aColor, TInt aBufferNumber)
+	{
+	RSurfaceManager::TInfoBuf infoBuf;
+	RSurfaceManager::TSurfaceInfoV01& info = infoBuf();
+
+	User::LeaveIfError(iManager.SurfaceInfo(aSurface, infoBuf));
+	TUint32 color = 0;
+	TBool use16 = EFalse;
+
+	if (info.iSize.iHeight<0 || info.iSize.iWidth<0 || info.iStride<0)
+		{
+		User::Leave(KErrCorrupt);
+		}
+	if (info.iSize.iHeight==0 || info.iSize.iWidth==0 || info.iStride==0)
+		{
+		User::Leave(KErrNotReady);
+		}
+
+	switch (info.iPixelFormat)
+		{
+		case EUidPixelFormatXRGB_8888:
+			{
+			color = aColor.Color16MU();
+#ifdef ALPHA_FIX_24BIT
+			color |= ((ALPHA_FIX_24BIT)&0xff)<<24;
+#endif
+			break;
+			}
+		case EUidPixelFormatARGB_8888:
+			{
+			color = aColor.Color16MA();
+			break;
+			}
+		case EUidPixelFormatARGB_8888_PRE:
+			{
+			color = aColor.Color16MAP();
+			break;
+			}
+		case EUidPixelFormatXRGB_4444:
+		case EUidPixelFormatARGB_4444:
+			{
+			color = aColor.Color4K();
+			use16 = ETrue;
+			break;
+			}
+		case EUidPixelFormatRGB_565:
+			{
+			color = aColor.Color64K();
+			use16 = ETrue;
+			break;
+			}
+		default:
+			{
+			User::Leave(KErrNotSupported);
+			break;
+			}
+		}
+
+	User::LeaveIfError(iManager.MapSurface(aSurface, aChunk));
+	
+	TInt offsetToFirstBuffer;
+	User::LeaveIfError(iManager.GetBufferOffset(aSurface, 0, offsetToFirstBuffer));
+	TInt offsetToBufferNumber;
+	User::LeaveIfError(iManager.GetBufferOffset(aSurface, aBufferNumber, offsetToBufferNumber));
+	
+	TUint8* chunkPtr = aChunk.Base() + offsetToFirstBuffer;
+	TUint8* linePtr = aChunk.Base() + offsetToBufferNumber;
+	TUint8* surfPlanePtr = linePtr;
+
+	if (use16)
+		{
+		if ( info.iSize.iWidth*2>info.iStride)
+			{
+			aChunk.Close();
+			User::Leave(KErrOverflow);
+			}
+		TUint16* ptr = reinterpret_cast<TUint16*>(surfPlanePtr);
+
+		// Fill first line
+		for (TInt xx = 0; xx < info.iSize.iWidth; xx++)
+			{
+			ptr[xx] = (TUint16)color;
+			}
+		}
+	else
+		{
+		if ( info.iSize.iWidth*4>info.iStride)
+			{
+			aChunk.Close();
+			User::Leave(KErrOverflow);
+			}
+		TUint32* ptr = reinterpret_cast<TUint32*>(surfPlanePtr);
+
+		// Fill first line
+		for (TInt xx = 0; xx < info.iSize.iWidth; xx++)
+			{
+			ptr[xx] = color;
+			}
+		}
+
+	// Now copy that to the other lines
+	for (TInt yy = 1; yy < info.iSize.iHeight; yy++)
+		{
+		linePtr += info.iStride;
+		Mem::Copy(linePtr, surfPlanePtr, info.iSize.iWidth * BytesPerPixelL(info.iPixelFormat));
+		}
+
+	aChunk.Close();
+	}
+
+/**
+Fill a rectangle on the given surface.
+
+@param aSurface		The surface to be filled.
+@param aStartPos	Where to place the rectangle.
+@param aSize		Size of the rectangle.
+@param aColor		The colour to fill it with.
+*/
+void CSurfaceUtility::FillRectangleL(TSurfaceId& aSurface, const TPoint& aStartPos, const TSize& aSize, const TRgb& aColor)
+	{
+	FillRectangleNoUpdateL(aSurface, aStartPos, aSize, aColor);
+	
+	TInt err = iSurfaceUpdateSession.SubmitUpdate(0, aSurface, 0, NULL);
+	if (err!=KErrNone)
+		LOG(("Error submitting update: 0x%X\n", err));
+	}
+
+/**
+Fill a rectangle on the given surface - does not submit update.
+
+@param aSurface		The surface to be filled.
+@param aStartPos	Where to place the rectangle.
+@param aSize		Size of the rectangle.
+@param aColor		The colour to fill it with.
+*/
+void CSurfaceUtility::FillRectangleNoUpdateL(TSurfaceId& aSurface, const TPoint& aStartPos, const TSize& aSize, const TRgb& aColor)
+	{
+	RSurfaceManager::TInfoBuf infoBuf;
+	RSurfaceManager::TSurfaceInfoV01& info = infoBuf();
+
+	User::LeaveIfError(iManager.SurfaceInfo(aSurface, infoBuf));
+	TUint32 color = 0;
+	TBool use16 = EFalse;
+
+	if (info.iSize.iHeight<0 || info.iSize.iWidth<0 || info.iStride<0)
+		{
+		User::Leave(KErrCorrupt);
+		}
+	if (info.iSize.iHeight==0 || info.iSize.iWidth==0 || info.iStride==0)
+		{
+		User::Leave(KErrNotReady);
+		}
+
+	switch (info.iPixelFormat)
+		{
+		case EUidPixelFormatXRGB_8888:
+			{
+			color = aColor.Color16MU();
+#ifdef ALPHA_FIX_24BIT
+			color |= ((ALPHA_FIX_24BIT)&0xff)<<24;
+#endif
+			break;
+			}
+		case EUidPixelFormatARGB_8888:
+			{
+			color = aColor.Color16MA();
+			break;
+			}
+		case EUidPixelFormatARGB_8888_PRE:
+			{
+			color = aColor.Color16MAP();
+			break;
+			}
+		case EUidPixelFormatXRGB_4444:
+		case EUidPixelFormatARGB_4444:
+			{
+			color = aColor.Color4K();
+			use16 = ETrue;
+			break;
+			}
+		case EUidPixelFormatRGB_565:
+			{
+			color = aColor.Color64K();
+			use16 = ETrue;
+			break;
+			}
+		default:
+			{
+			User::Leave(KErrNotSupported);
+			break;
+			}
+		}
+
+	RChunk chunk;
+	User::LeaveIfError(iManager.MapSurface(aSurface, chunk));
+	CleanupClosePushL(chunk);
+
+	TInt offsetToFirstBuffer;
+	User::LeaveIfError(iManager.GetBufferOffset(aSurface, 0, offsetToFirstBuffer));
+	TUint8* surfacePtr = chunk.Base() + offsetToFirstBuffer;
+	
+	// Check for out of bounds
+	TBool validRect = ETrue;
+	TInt surfaceWidth = info.iSize.iWidth;
+	TInt surfaceHeight = info.iSize.iHeight;
+	
+	// Width and Height
+	if ((aStartPos.iX + aSize.iWidth) > surfaceWidth)
+		validRect = EFalse;
+	
+	if ((aStartPos.iY + aSize.iHeight) > surfaceHeight)
+		validRect = EFalse;
+	
+	// Starting position
+	if ((aStartPos.iX < 0) || (aStartPos.iY < 0))
+		validRect = EFalse;
+	
+	if (!validRect)
+		User::Leave(KErrOverflow);
+		
+	if (use16)
+		{
+		if ( info.iSize.iWidth*2>info.iStride)
+			{
+			User::Leave(KErrOverflow);
+			}
+		
+		TUint16* ptr = reinterpret_cast<TUint16*>(surfacePtr);
+		
+		// Fill the rectangle
+		TInt yPos = aStartPos.iY;
+		TInt xPos = aStartPos.iX;
+		for (TInt yy = 0; yy < aSize.iHeight; ++yy)
+			{
+			ptr = reinterpret_cast<TUint16*>(surfacePtr+(yPos*info.iStride));
+			for (TInt xx = 0; xx < aSize.iWidth; ++xx)
+				{
+				ptr[xPos] = color;
+				xPos++;
+				}
+			xPos = aStartPos.iX;
+			yPos++;
+			}
+		}
+	else
+		{
+		if ( info.iSize.iWidth*4>info.iStride)
+			{
+			User::Leave(KErrOverflow);
+			}
+
+		TUint32* ptr = reinterpret_cast<TUint32*>(surfacePtr);		
+		
+		// Fill the rectangle
+		TInt yPos = aStartPos.iY;
+		TInt xPos = aStartPos.iX;
+		for (TInt yy = 0; yy < aSize.iHeight; ++yy)
+			{
+			ptr = reinterpret_cast<TUint32*>(surfacePtr+(yPos*info.iStride));
+			for (TInt xx = 0; xx < aSize.iWidth; ++xx)
+				{
+				ptr[xPos] = color;
+				xPos++;
+				}
+			xPos = aStartPos.iX;
+			yPos++;
+			}
+		}
+	
+	CleanupStack::PopAndDestroy(/* chunk */);
+	}
+
+/**
+Fill the given surface with a grid over a solid color.
+
+Similar to FillSurfaceL(), but with a grid overlayed. The pitch of the grid is
+eight pixels.
+
+@param aSurface	The surface to be filled.
+@param aColor	The color to fill it with.
+@param aLines	The color of the grid lines.
+*/
+void CSurfaceUtility::GridFillSurfaceL(TSurfaceId& aSurface, const TRgb& aColor, const TRgb& aLines)
+	{
+	RSurfaceManager::TInfoBuf infoBuf;
+	RSurfaceManager::TSurfaceInfoV01& info = infoBuf();
+
+	User::LeaveIfError(iManager.SurfaceInfo(aSurface, infoBuf));
+	TUint32 color = 0;
+	TUint32 lines = 0;
+	TBool use16 = EFalse;
+
+	if (info.iSize.iHeight<0 || info.iSize.iWidth<0 || info.iStride<0)
+		{
+		User::Leave(KErrCorrupt);
+		}
+	if (info.iSize.iHeight==0 || info.iSize.iWidth==0 || info.iStride==0)
+		{
+		User::Leave(KErrNotReady);
+		}
+
+	switch (info.iPixelFormat)
+		{
+		case EUidPixelFormatXRGB_8888:
+			{
+			color = aColor.Color16MU();
+			lines = aLines.Color16MU();
+#ifdef ALPHA_FIX_24BIT
+			color |= ((ALPHA_FIX_24BIT)&0xff)<<24;
+			lines |= ((ALPHA_FIX_24BIT)&0xff)<<24;
+#endif
+			break;
+			}
+		case EUidPixelFormatARGB_8888:
+			{
+			color = aColor.Color16MA();
+			lines = aLines.Color16MA();
+			break;
+			}
+		case EUidPixelFormatARGB_8888_PRE:
+			{
+			color = aColor.Color16MAP();
+			lines = aLines.Color16MAP();
+			break;
+			}
+		case EUidPixelFormatXRGB_4444:
+		case EUidPixelFormatARGB_4444:
+			{
+			color = aColor.Color4K();
+			lines = aLines.Color4K();
+			use16 = ETrue;
+			break;
+			}
+		case EUidPixelFormatRGB_565:
+			{
+			color = aColor.Color64K();
+			lines = aLines.Color64K();
+			use16 = ETrue;
+			break;
+			}
+		default:
+			{
+			User::Leave(KErrNotSupported);
+			break;
+			}
+		}
+
+	RChunk chunk;
+	User::LeaveIfError(iManager.MapSurface(aSurface, chunk));
+	CleanupClosePushL(chunk);
+
+	TInt offsetToFirstBuffer;
+	User::LeaveIfError(iManager.GetBufferOffset(aSurface, 0, offsetToFirstBuffer));
+	TUint8* surfacePtr = chunk.Base() + offsetToFirstBuffer;
+	TUint8* linePtr = surfacePtr;
+
+	if (use16)
+		{
+		if ( info.iSize.iWidth*2>info.iStride)
+			{
+			User::Leave(KErrOverflow);
+			}
+		TUint16* ptr = reinterpret_cast<TUint16*>(surfacePtr);
+
+		// Fill first line
+		for (TInt xx1 = 0; xx1 < info.iSize.iWidth; xx1++)
+			{
+			ptr[xx1] = (TUint16)lines;
+			}
+
+		// Fill second line
+		ptr = reinterpret_cast<TUint16*>(surfacePtr + info.iStride);
+		for (TInt xx2 = 0; xx2 < info.iSize.iWidth; xx2++)
+			{
+			// Vertical line every 8 pixels across
+			ptr[xx2] = (TUint16)((xx2 & 7) ? color : lines);
+			}
+		}
+	else
+		{
+		if ( info.iSize.iWidth*4>info.iStride)
+			{
+			User::Leave(KErrOverflow);
+			}
+		TUint32* ptr = reinterpret_cast<TUint32*>(surfacePtr);
+
+		// Fill first line
+		for (TInt xx3 = 0; xx3 < info.iSize.iWidth; xx3++)
+			{
+			ptr[xx3] = lines;
+			}
+
+		// Fill second line
+		ptr = reinterpret_cast<TUint32*>(surfacePtr + info.iStride);
+		for (TInt xx4 = 0; xx4 < info.iSize.iWidth; xx4++)
+			{
+			// Vertical line every 8 pixels across
+			ptr[xx4] = (xx4 & 7) ? color : lines;
+			}
+		}
+	linePtr += info.iStride;
+
+	// Now copy that to the other lines
+	for (TInt yy = 2; yy < info.iSize.iHeight; yy++)
+		{
+		linePtr += info.iStride;
+		if (yy & 7)
+			{
+			// Copy second line
+			Mem::Copy(linePtr, surfacePtr + info.iStride, info.iSize.iWidth * BytesPerPixelL(info.iPixelFormat));
+			}
+		else
+			{
+			// Copy first line
+			Mem::Copy(linePtr, surfacePtr, info.iSize.iWidth * BytesPerPixelL(info.iPixelFormat));
+			}
+		}
+
+	TInt err =iSurfaceUpdateSession.SubmitUpdate(0, aSurface, 0, NULL);
+	if (err!=KErrNone)
+		LOG(("Error submitting update: 0x%X\n", err));
+	
+	CleanupStack::PopAndDestroy(/* chunk */);
+	}
+
+
+/**
+Fill the given surface with a pattern suitable for automated testing.
+
+@param aSurface	The surface to be filled.
+*/
+void CSurfaceUtility::PatternFillSurfaceL(TSurfaceId& aSurface)
+	{
+	RSurfaceManager::TInfoBuf infoBuf;
+	RSurfaceManager::TSurfaceInfoV01& info = infoBuf();
+
+	User::LeaveIfError(iManager.SurfaceInfo(aSurface, infoBuf));	
+	
+	// Fill the background
+	FillSurfaceL(aSurface, TRgb(0x00000000));
+
+	TInt surfaceWidth = info.iSize.iWidth;
+	TInt surfaceHeight = info.iSize.iHeight;
+	
+	// Create the 4 rectangles in the corners
+	TPoint startPos(0,0);
+	TSize size(15,15);
+	TInt rectWidth = size.iWidth;
+	TInt rectHeight = size.iHeight;
+	// Top left
+	FillRectangleL(aSurface, startPos, size, TRgb(0x0000ff));
+	
+	// Top right
+	startPos.iX = surfaceWidth - rectWidth;
+	startPos.iY = 0;
+	FillRectangleL(aSurface, startPos, size, TRgb(0x00ff00));
+	
+	// Bottom left
+	startPos.iX = 0;
+	startPos.iY = surfaceHeight - rectHeight;
+	FillRectangleL(aSurface, startPos, size, TRgb(0x00ffff));
+	
+	// Bottom right
+	startPos.iX = surfaceWidth - rectWidth;
+	startPos.iY = surfaceHeight - rectHeight;
+	FillRectangleL(aSurface, startPos, size, TRgb(0xffffff));
+	
+	// Create the 4 side bars
+	startPos.iX = 0;
+	startPos.iY = 6;
+	size.iWidth = 5;
+	size.iHeight = surfaceHeight - 12;
+	// Left
+	FillRectangleL(aSurface, startPos, size, TRgb(0x808000));
+	
+	startPos.iX = surfaceWidth - size.iWidth;
+	startPos.iY = 6;
+	// Right
+	FillRectangleL(aSurface, startPos, size, TRgb(0xff00ff));
+	
+	startPos.iX = 6;
+	startPos.iY = surfaceHeight - size.iWidth;
+	size.iWidth = surfaceWidth - 12;
+	size.iHeight = 5;
+	// Top
+	FillRectangleL(aSurface, startPos, size, TRgb(0xaaaaaa));
+	
+	startPos.iX = 6;
+	startPos.iY = 0;
+	// Bottom
+	FillRectangleL(aSurface, startPos, size, TRgb(0x000080));
+	}
+
+
+template <class TIntType> void
+DdaLine(TUint aX1, TUint aY1,TUint aX2,TUint aY2, TUint aPixPerScan, TIntType* aBuffer, TIntType aColor)
+	{
+	TInt dx=aX2-aX1;
+	TInt dy=aY2-aY1;
+	TInt adx=dx,sdx=1;
+	if (adx<0)
+		{	adx=-adx; sdx=-1;	}
+	TInt ady=dy,sdy=aPixPerScan;
+	if (ady<0)
+		{	ady=-ady; sdy=-aPixPerScan;	}
+	//This is simplistic integert DDA.
+	//The vertical cases are handled by this 1/2 accumulator:
+	//	If adx is zero then we step in sdy indefinitely
+	//  If ady is zero then we step in sdx indefinitely
+	TInt accum=adx/2;
+	
+	TIntType* bufferend=aBuffer+aX2+aY2*aPixPerScan;
+	aBuffer+=aX1+aY1*aPixPerScan;
+	*aBuffer=aColor;
+	while (aBuffer!=bufferend)
+		{
+		if (accum>0)
+			{
+			accum-=ady;
+			aBuffer+=sdx;
+			}
+		else
+			{
+			accum+=adx;
+			aBuffer+=sdy;
+			}
+		*aBuffer=aColor;
+		}
+	
+
+	}
+template <class TIntType> void	
+FanFill(const TPoint& aInnerXY,TUint aPixPerScan, TIntType* aSurfacePtr, TIntType aLinesTL, 
+			TIntType aLinesBR, TIntType aLinesTR, TIntType aLinesBL)
+	{
+	
+		DdaLine(aInnerXY.iX,0,aInnerXY.iX-aInnerXY.iX*180/1024,aInnerXY.iY,aPixPerScan,aSurfacePtr,aLinesTR);
+		DdaLine(aInnerXY.iX,0,aInnerXY.iX-aInnerXY.iX*372/1024,aInnerXY.iY,aPixPerScan,aSurfacePtr,aLinesTR);
+		DdaLine(aInnerXY.iX,0,aInnerXY.iX-aInnerXY.iX*591/1024,aInnerXY.iY,aPixPerScan,aSurfacePtr,aLinesTR);
+		DdaLine(aInnerXY.iX,0,aInnerXY.iX-aInnerXY.iX*859/1024,aInnerXY.iY,aPixPerScan,aSurfacePtr,aLinesTR);
+
+		DdaLine(aInnerXY.iX,0,0,aInnerXY.iY*180/1024,aPixPerScan,aSurfacePtr,aLinesTR);
+		DdaLine(aInnerXY.iX,0,0,aInnerXY.iY*372/1024,aPixPerScan,aSurfacePtr,aLinesTR);
+		DdaLine(aInnerXY.iX,0,0,aInnerXY.iY*591/1024,aPixPerScan,aSurfacePtr,aLinesTR);
+		DdaLine(aInnerXY.iX,0,0,aInnerXY.iY*859/1024,aPixPerScan,aSurfacePtr,aLinesTR);
+		
+		DdaLine(0,aInnerXY.iY,aInnerXY.iX*180/1024,0,aPixPerScan,aSurfacePtr,aLinesBL);
+		DdaLine(0,aInnerXY.iY,aInnerXY.iX*372/1024,0,aPixPerScan,aSurfacePtr,aLinesBL);
+		DdaLine(0,aInnerXY.iY,aInnerXY.iX*591/1024,0,aPixPerScan,aSurfacePtr,aLinesBL);
+		DdaLine(0,aInnerXY.iY,aInnerXY.iX*859/1024,0,aPixPerScan,aSurfacePtr,aLinesBL);
+
+		DdaLine(0,aInnerXY.iY,aInnerXY.iX,aInnerXY.iY-aInnerXY.iY*180/1024,aPixPerScan,aSurfacePtr,aLinesBL);
+		DdaLine(0,aInnerXY.iY,aInnerXY.iX,aInnerXY.iY-aInnerXY.iY*372/1024,aPixPerScan,aSurfacePtr,aLinesBL);
+		DdaLine(0,aInnerXY.iY,aInnerXY.iX,aInnerXY.iY-aInnerXY.iY*591/1024,aPixPerScan,aSurfacePtr,aLinesBL);
+		DdaLine(0,aInnerXY.iY,aInnerXY.iX,aInnerXY.iY-aInnerXY.iY*859/1024,aPixPerScan,aSurfacePtr,aLinesBL);
+		
+		DdaLine(0,0,aInnerXY.iX*180/1024,aInnerXY.iY,aPixPerScan,aSurfacePtr,aLinesTL);
+		DdaLine(0,0,aInnerXY.iX*372/1024,aInnerXY.iY,aPixPerScan,aSurfacePtr,aLinesTL);
+		DdaLine(0,0,aInnerXY.iX*591/1024,aInnerXY.iY,aPixPerScan,aSurfacePtr,aLinesTL);
+		DdaLine(0,0,aInnerXY.iX*859/1024,aInnerXY.iY,aPixPerScan,aSurfacePtr,aLinesTL);
+
+		DdaLine(0,0,aInnerXY.iX,aInnerXY.iY*180/1024,aPixPerScan,aSurfacePtr,aLinesTL);
+		DdaLine(0,0,aInnerXY.iX,aInnerXY.iY*372/1024,aPixPerScan,aSurfacePtr,aLinesTL);
+		DdaLine(0,0,aInnerXY.iX,aInnerXY.iY*591/1024,aPixPerScan,aSurfacePtr,aLinesTL);
+		DdaLine(0,0,aInnerXY.iX,aInnerXY.iY*859/1024,aPixPerScan,aSurfacePtr,aLinesTL);
+		
+		DdaLine(0,aInnerXY.iY-aInnerXY.iY*180/1024,aInnerXY.iX,aInnerXY.iY,aPixPerScan,aSurfacePtr,aLinesBR);
+		DdaLine(0,aInnerXY.iY-aInnerXY.iY*372/1024,aInnerXY.iX,aInnerXY.iY,aPixPerScan,aSurfacePtr,aLinesBR);
+		DdaLine(0,aInnerXY.iY-aInnerXY.iY*591/1024,aInnerXY.iX,aInnerXY.iY,aPixPerScan,aSurfacePtr,aLinesBR);
+		DdaLine(0,aInnerXY.iY-aInnerXY.iY*859/1024,aInnerXY.iX,aInnerXY.iY,aPixPerScan,aSurfacePtr,aLinesBR);
+
+		DdaLine(aInnerXY.iX-aInnerXY.iX*180/1024,0,aInnerXY.iX,aInnerXY.iY,aPixPerScan,aSurfacePtr,aLinesBR);
+		DdaLine(aInnerXY.iX-aInnerXY.iX*372/1024,0,aInnerXY.iX,aInnerXY.iY,aPixPerScan,aSurfacePtr,aLinesBR);
+		DdaLine(aInnerXY.iX-aInnerXY.iX*591/1024,0,aInnerXY.iX,aInnerXY.iY,aPixPerScan,aSurfacePtr,aLinesBR);
+		DdaLine(aInnerXY.iX-aInnerXY.iX*859/1024,0,aInnerXY.iX,aInnerXY.iY,aPixPerScan,aSurfacePtr,aLinesBR);
+	
+	}
+/**
+Fill the given surface with a fan of lines over a solid color.
+
+Similar to FillSurfaceL(), but with a fan of lines overlayed. 
+One fan is drawn about the top-left, and second fan at bottom-right.
+The fan contains 8 segments.
+
+@param aSurface	The surface to be filled.
+@param aColor	The color to fill it with.
+@param aLines	The color of the grid lines.
+*/
+void CSurfaceUtility::FanFillSurfaceL(TSurfaceId& aSurface, const TRgb& aColor, const TRgb& aLinesTL, const TRgb& aLinesBR)
+	{
+	FillSurfaceL(aSurface,aColor);
+	RSurfaceManager::TInfoBuf infoBuf;
+	RSurfaceManager::TSurfaceInfoV01& info = infoBuf();
+
+	User::LeaveIfError(iManager.SurfaceInfo(aSurface, infoBuf));
+	TUint32 linesTL = 0;
+	TUint32 linesBR = 0;
+	TUint32 linesTR = 0;
+	TUint32 linesBL = 0;
+	TBool use16 = EFalse;
+	TRgb	rgbLinesTR(0,0,0);
+	TRgb	rgbLinesBL(255,255,255);
+
+	switch (info.iPixelFormat)
+		{
+		case EUidPixelFormatXRGB_8888:
+			{
+			linesBR = aLinesBR.Color16MU();
+			linesTL = aLinesTL.Color16MU();
+			linesTR = rgbLinesTR.Color16MU();
+			linesBL = rgbLinesBL.Color16MU();
+#ifdef ALPHA_FIX_24BIT
+			linesBR |= ((ALPHA_FIX_24BIT)&0xff)<<24;
+			linesTL |= ((ALPHA_FIX_24BIT)&0xff)<<24;
+			linesTR |= ((ALPHA_FIX_24BIT)&0xff)<<24;
+			linesBL |= ((ALPHA_FIX_24BIT)&0xff)<<24;
+#endif
+			break;
+			}
+		case EUidPixelFormatARGB_8888:
+			{
+			linesBR = aLinesBR.Color16MA();
+			linesTL = aLinesTL.Color16MA();
+			linesTR = rgbLinesTR.Color16MA();
+			linesBL = rgbLinesBL.Color16MA();
+			break;
+			}
+		case EUidPixelFormatARGB_8888_PRE:
+			{
+			linesBR = aLinesBR.Color16MAP();
+			linesTL = aLinesTL.Color16MAP();
+			linesTR = rgbLinesTR.Color16MAP();
+			linesBL = rgbLinesBL.Color16MAP();
+			break;
+			}
+		case EUidPixelFormatXRGB_4444:
+		case EUidPixelFormatARGB_4444:
+			{
+			linesBR = aLinesBR.Color4K();
+			linesTL = aLinesTL.Color4K();
+			linesTR = rgbLinesTR.Color4K();
+			linesBL = rgbLinesBL.Color4K();
+			use16 = ETrue;
+			break;
+			}
+		case EUidPixelFormatRGB_565:
+			{
+			linesBR = aLinesBR.Color64K();
+			linesTL = aLinesTL.Color64K();
+			linesTR = rgbLinesTR.Color64K();
+			linesBL = rgbLinesBL.Color64K();
+			use16 = ETrue;
+			break;
+			}
+		default:
+			{
+			User::Leave(KErrNotSupported);
+			break;
+			}
+		}
+	if (info.iSize.iHeight<0 || info.iSize.iWidth<0 || info.iStride<0)
+		{
+		User::Leave(KErrCorrupt);
+		}
+	if (info.iSize.iHeight==0 || info.iSize.iWidth==0 || info.iStride==0)
+		{
+		User::Leave(KErrNotReady);
+		}
+	RChunk chunk;
+	User::LeaveIfError(iManager.MapSurface(aSurface, chunk));
+	CleanupClosePushL(chunk);
+	
+	TInt offsetToFirstBuffer;
+	User::LeaveIfError(iManager.GetBufferOffset(aSurface, 0, offsetToFirstBuffer));
+	TUint8* surfacePtr = chunk.Base() + offsetToFirstBuffer;
+	TPoint innerXY(info.iSize.iWidth-1,info.iSize.iHeight-1);
+	if (use16)
+		{
+		if ( info.iSize.iWidth*2>info.iStride)
+			{
+			User::Leave(KErrOverflow);
+			}
+		FanFill<TUint16>(innerXY,info.iStride/2,(TUint16*)surfacePtr,linesTL,linesBR,linesBL,linesTR);
+		}
+	else
+		{
+		if ( info.iSize.iWidth*4>info.iStride)
+			{
+			User::Leave(KErrOverflow);
+			}
+		FanFill<TUint>(innerXY,info.iStride/4,(TUint*)surfacePtr,linesTL,linesBR,linesBL,linesTR);
+		}
+	
+	iSurfaceUpdateSession.SubmitUpdate(0, aSurface, 0, NULL);
+	
+	CleanupStack::PopAndDestroy(/* chunk */);
+	}
+/**
+Fill the given surface with vertical line at the given position
+
+Similar to FillSurfaceL(), but with a vertical line overlayed. 
+The position along the surface is given as a percentage from the left
+
+@param aSurface	The surface to be filled.
+@param aColor	The color to fill it with.
+@param aLine	The color of the line.
+@param aPosition Position of the vertical line given as a percentage across the surface from the left edge
+*/
+void CSurfaceUtility::LineFillSurfaceL(TSurfaceId& aSurface, const TRgb& aBackColor, const TRgb& aLineColor, TInt aPosition)
+	{
+	if (aPosition<0 || aPosition>100)
+		{
+		aPosition=0;
+		}
+	FillSurfaceL(aSurface,aBackColor);
+	RSurfaceManager::TInfoBuf infoBuf;
+	RSurfaceManager::TSurfaceInfoV01& info = infoBuf();
+	
+	User::LeaveIfError(iManager.SurfaceInfo(aSurface, infoBuf));
+	TUint32 lineColor = 0;
+	TBool use16 = EFalse;
+	
+	switch (info.iPixelFormat)
+		{
+		case EUidPixelFormatXRGB_8888:
+			{
+			lineColor = aLineColor.Color16MU();
+#ifdef ALPHA_FIX_24BIT
+			lineColor |= ((ALPHA_FIX_24BIT)&0xff)<<24;
+#endif
+			break;
+			}
+		case EUidPixelFormatARGB_8888:
+			{
+			lineColor = aLineColor.Color16MA();
+			break;
+			}
+		case EUidPixelFormatARGB_8888_PRE:
+			{
+			lineColor = aLineColor.Color16MAP();
+			break;
+			}
+		case EUidPixelFormatXRGB_4444:
+		case EUidPixelFormatARGB_4444:
+			{
+			lineColor = aLineColor.Color4K();
+			use16 = ETrue;
+			break;
+			}
+		case EUidPixelFormatRGB_565:
+			{
+			lineColor = aLineColor.Color64K();
+			use16 = ETrue;
+			break;
+			}
+		default:
+			{
+			User::Leave(KErrNotSupported);
+			break;
+			}
+		}
+	RChunk chunk;
+	User::LeaveIfError(iManager.MapSurface(aSurface, chunk));
+	
+	TInt offsetToFirstBuffer;
+	User::LeaveIfError(iManager.GetBufferOffset(aSurface, 0, offsetToFirstBuffer));
+	TUint8* surfacePtr = chunk.Base() + offsetToFirstBuffer;
+	if (use16)
+		{
+		DdaLine<TUint16>((info.iSize.iWidth*aPosition)/100,0,(info.iSize.iWidth*aPosition)/100,
+				info.iSize.iHeight-1,info.iStride/2,(TUint16*)surfacePtr,lineColor);
+		}
+	else
+		{
+		DdaLine<TUint>((info.iSize.iWidth*aPosition)/100,0,(info.iSize.iWidth*aPosition)/100,
+				info.iSize.iHeight-1,info.iStride/4,(TUint*)surfacePtr,lineColor);
+		}
+
+	chunk.Close();
+	
+	iSurfaceUpdateSession.SubmitUpdate(0, aSurface, 0, NULL);
+	}
+/**
+ * Generates a bitmap equivalent to the surface.
+ * Can reuse an existing bitmap or create a new bitmap.
+ * The existing bitmap must be an exact match (eg previously generated by this method)
+ **/
+CFbsBitmap* CSurfaceUtility::EquivalentBitmapL(TSurfaceId& aSurface,CFbsBitmap* aCopyToMayBeNull)
+	{
+	RSurfaceManager::TInfoBuf infoBuf;
+	RSurfaceManager::TSurfaceInfoV01& info = infoBuf();
+
+	User::LeaveIfError(iManager.SurfaceInfo(aSurface, infoBuf));
+	TInt bytesPerPixel=0;
+	TDisplayMode	bitmapMode = ENone;
+	switch (info.iPixelFormat)
+		{
+		case EUidPixelFormatXRGB_8888:
+			{
+			bitmapMode = EColor16MU;
+			bytesPerPixel = 4;
+			break;
+			}
+		case EUidPixelFormatARGB_8888:
+			{
+			bitmapMode=EColor16MA;
+			bytesPerPixel = 4;
+			break;
+			}
+		case EUidPixelFormatARGB_8888_PRE:
+			{
+			bitmapMode=EColor16MAP;
+			bytesPerPixel = 4;
+			break;
+			}
+		case EUidPixelFormatXRGB_4444:
+		case EUidPixelFormatARGB_4444:
+			{
+			bitmapMode=EColor4K;
+			bytesPerPixel = 2;
+			break;
+			}
+		case EUidPixelFormatRGB_565:
+			{
+			bitmapMode=EColor64K;
+			bytesPerPixel = 2;
+			break;
+			}
+		default:
+			{
+			User::Leave(KErrNotSupported);
+			break;
+			}
+		}
+	CFbsBitmap* retVal=NULL;
+	if (aCopyToMayBeNull)
+		{
+		retVal=aCopyToMayBeNull;
+		if (retVal->SizeInPixels()!=info.iSize)
+			User::Leave(KErrCorrupt);
+		if (retVal->DisplayMode()!=bitmapMode)
+			User::Leave(KErrCorrupt);
+		}
+	else
+		{
+		retVal=new CFbsBitmap;
+		CleanupStack::PushL(retVal);
+		User::LeaveIfError(retVal->Create(info.iSize,bitmapMode));
+		}
+	RChunk chunk;
+	CleanupClosePushL(chunk);
+	User::LeaveIfError(iManager.MapSurface(aSurface, chunk));
+	TInt offsetToFirstBuffer;
+	User::LeaveIfError(iManager.GetBufferOffset(aSurface, 0, offsetToFirstBuffer));
+	TUint8* surfacePtr = chunk.Base() + offsetToFirstBuffer;
+	TUint8* bitmapPtr = (TUint8*)retVal->DataAddress();
+	TInt copyBytes=info.iSize.iWidth*bytesPerPixel;
+	for (TInt y=0;y<info.iSize.iHeight;y++)
+		{
+		Mem::Copy(bitmapPtr,surfacePtr,copyBytes);
+		surfacePtr+=info.iStride;
+		bitmapPtr+=retVal->DataStride();
+		}
+	CleanupStack::PopAndDestroy(&chunk);
+	if (!aCopyToMayBeNull)
+		CleanupStack::Pop(retVal);
+	return retVal;
+	}
+
+/**
+Destroy a surface.
+
+As well as destroying the surface, it is removed from the set held for
+destruction during tear down.
+
+@param aSurface	The surface to be destroyed.
+*/
+void CSurfaceUtility::DestroySurface(TSurfaceId& aSurface)
+	{
+	TInt index = iSurfaces.Find(aSurface);
+	
+	if (index != KErrNotFound)
+		{
+		iSurfaces.Remove(index);
+		}
+
+	TInt err = iManager.CloseSurface(aSurface);
+	if (err!=KErrNone)
+		LOG(("Error closing surfaces: 0x%X\n", err));
+	}
+
+
+/**
+Submit an update to a surface to the update server.
+
+@param aScreenNumber	The screen to be updated where the surface is shown.
+@param aSurface	The surface which has been updated.
+@param aRegion	The area of the surface affected, or NULL for all of it.*/
+void CSurfaceUtility::SubmitUpdate(TInt aScreenNumber, const TSurfaceId& aSurface, const TRegion* aRegion,TInt aBufferNumber)
+	{
+	TInt err =iSurfaceUpdateSession.SubmitUpdate(aScreenNumber, aSurface, aBufferNumber, aRegion); 
+	if (err!=KErrNone)
+		LOG(("Error submitting update: 0x%X\n", err));
+	}
+
+/**
+Map and submit an update to a surface to the update server.
+
+@param aChunk	The chunk of memory to be mapped
+@param aScreenNumber	The screen to be updated where the surface is shown.
+@param aSurface	The surface which has been updated.
+@param aRegion	The area of the surface affected, or NULL for all of it.*/
+void CSurfaceUtility::MapAndSubmitUpdateL(RChunk& aChunk, 
+		                                TInt aScreenNumber, 
+		                                const TSurfaceId& aSurface, 
+		                                const TRegion* aRegion)
+	{
+	User::LeaveIfError(iManager.MapSurface(aSurface, aChunk));
+	aChunk.Close();
+	TInt err =iSurfaceUpdateSession.SubmitUpdate(aScreenNumber, aSurface, 0, aRegion); 
+	if (err!=KErrNone)
+		LOG(("Error submitting update: 0x%X\n", err));
+	}
+
+void CSurfaceUtility::MapSurfaceL(const TSurfaceId& aSurface, RChunk& aChunk)
+	{
+	User::LeaveIfError(iManager.MapSurface(aSurface, aChunk));
+	}
+
+void CSurfaceUtility::CopyBitmapToSurfaceL(TSurfaceId& aSurface, const CFbsBitmap& aBitmap)
+	{
+	TSize size = SurfaceSize(aSurface);
+	
+	TDisplayMode bmpFormat = aBitmap.DisplayMode();
+	TInt stride = size.iWidth * 4;		// Default to four bytes per pixel
+
+	RChunk chunk;
+	User::LeaveIfError(iManager.MapSurface(aSurface, chunk));
+	CleanupClosePushL(chunk);
+
+	TInt offsetToFirstBuffer;
+	User::LeaveIfError(iManager.GetBufferOffset(aSurface, 0, offsetToFirstBuffer));
+
+	// Copy the data from the bitmap into the surface.
+	TPoint start;
+	TUint8 *pSurfStart = chunk.Base() + offsetToFirstBuffer;
+	for (start.iY = 0; start.iY < size.iHeight; start.iY++)
+		{
+		// Set up a descriptor for the current line in the surface and get pixels.
+		TPtr8 ptr(pSurfStart + start.iY * stride, stride);
+		aBitmap.GetScanLine(ptr, start, size.iWidth, bmpFormat);
+		}
+
+	TInt err =iSurfaceUpdateSession.SubmitUpdate(0, aSurface, 0, NULL);
+	if (err!=KErrNone)
+		{
+		LOG(("Error submitting update: 0x%X\n", err));
+		}
+
+	CleanupStack::PopAndDestroy(/* chunk */);
+	}