graphicscomposition/openwftest/src/surfaceutility.cpp
changeset 152 9f1c3fea0f87
equal deleted inserted replaced
111:29ddb8a72f0e 152:9f1c3fea0f87
       
     1 // Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 /**
       
    17  @file
       
    18 */
       
    19 
       
    20 #include <e32std.h>
       
    21 #include <imageconversion.h>
       
    22 #include <stdlib.h>
       
    23 #include <s32file.h> 
       
    24 #include "surfaceutility.h"
       
    25 
       
    26 #ifdef __cplusplus
       
    27 extern "C" {
       
    28 #endif
       
    29 
       
    30 WFC_API_CALL WFCNativeStreamType WFC_APIENTRY
       
    31 extwfcGetOnScreenStream(WFCDevice dev, WFCContext context) WFC_APIEXIT;
       
    32 
       
    33 #ifdef __cplusplus
       
    34 }
       
    35 #endif
       
    36 
       
    37 CSurfaceUtility::CSurfaceUtility()
       
    38 : iSurfaces(NULL)
       
    39 	{
       
    40 	}
       
    41 	
       
    42 CSurfaceUtility* CSurfaceUtility::NewL()
       
    43 	{
       
    44 	CSurfaceUtility* utility = new (ELeave)CSurfaceUtility();
       
    45 	CleanupStack::PushL(utility);
       
    46 	utility->ConstructL();
       
    47 	CleanupStack::Pop(utility);
       
    48 	return utility;
       
    49 	}
       
    50 	
       
    51 void CSurfaceUtility::ConstructL()
       
    52 	{
       
    53 	TInt r = iManager.Open();
       
    54 	if (r != KErrNone)
       
    55 		{
       
    56 		LOG(("Surface manager failed to open: %d", r));
       
    57 		User::Leave(r);
       
    58 		}
       
    59 	
       
    60 	r = iSurfaceUpdateSession.Connect();
       
    61 	if (r != KErrNone)
       
    62 		{
       
    63 		LOG(("Failed to connect to update server: %d", r));
       
    64 		User::Leave(r);
       
    65 		}	
       
    66 	}
       
    67 
       
    68 CSurfaceUtility::~CSurfaceUtility()
       
    69 	{
       
    70 	DestroyAll();
       
    71 
       
    72 	iSurfaces.Close();
       
    73 
       
    74 	iManager.Close();
       
    75 
       
    76 	iSurfaceUpdateSession.Close();	
       
    77 	}
       
    78 
       
    79 TBool CSurfaceUtility::DestroyAll()
       
    80 	{
       
    81 	TInt err = 	KErrNone;
       
    82 	TInt jj = iSurfaces.Count() - 1;
       
    83 	if (jj<0)
       
    84 		return EFalse;
       
    85 	for (; jj >= 0; jj--)
       
    86 		{
       
    87 		err = iManager.CloseSurface(iSurfaces[jj]);
       
    88 		if (err!=KErrNone)
       
    89 			{
       
    90 			LOG(("Error closing surface: 0x%X\n", err));
       
    91 			}
       
    92 		TInt offset;
       
    93 		err = iManager.GetBufferOffset(iSurfaces[jj],0,offset);
       
    94 		if (err==KErrNone)
       
    95 		    {
       
    96             LOG(("Error: closed surface still accessible: index %i surface %08X %08X %08X %08X\n", jj, iSurfaces[jj]));
       
    97 		    }
       
    98 		}
       
    99 	iSurfaces.Reset();
       
   100 	return ETrue;
       
   101 	}
       
   102 
       
   103 /***************************************
       
   104  * The aim of the THeapSurfaceArray is to locally switch in the specified heap for any array operation
       
   105  ***************************************/
       
   106 
       
   107 CSurfaceUtility::RHeapSurfaceArray::RHeapSurfaceArray(RHeapSurfaceArray* aUseExternalArray)
       
   108 	:	iUseArray(aUseExternalArray?aUseExternalArray->iUseArray:&this->iLocalArray),
       
   109 	iExternalHeapRef(aUseExternalArray?aUseExternalArray->iExternalHeapRef:User::Heap())
       
   110 	{
       
   111 	
       
   112 	}
       
   113 /************************************
       
   114  * The following methods have been used by the surfaceutility... some require the heap wrapping, and some don't
       
   115  * Three strategies are needed for 7 methods...
       
   116  * Some methods only read the existing objects, so don't need a heap swap at all
       
   117  * Leaving methods have to use PopAndDestroy strategy to restore the heap on leaving or success
       
   118  * Non-leaving methods must not call PushL, so directly make SwitchHeap calls!
       
   119  ************************************/
       
   120 
       
   121 // PopAndDestroy method to restore the heap
       
   122 /*static*/ void	CSurfaceUtility::RHeapSurfaceArray::PopHeap(void* aHeapPtr)
       
   123 	{
       
   124 	RHeap* heapPtr=(RHeap*)aHeapPtr;
       
   125 	User::SwitchHeap(heapPtr);
       
   126 	}
       
   127 
       
   128 TSurfaceId& CSurfaceUtility::RHeapSurfaceArray::operator[](TUint aIndex)
       
   129 	{
       
   130 	return iUseArray->operator[](aIndex);
       
   131 	}
       
   132 
       
   133 // Close only closes the local array, while Reset resets the active array (may be external)
       
   134 void CSurfaceUtility::RHeapSurfaceArray::Close()
       
   135 	{
       
   136 	iLocalArray.Close();
       
   137 	}
       
   138 
       
   139 TInt CSurfaceUtility::RHeapSurfaceArray::Count() const
       
   140 	{
       
   141 	return iUseArray->Count();
       
   142 	}
       
   143 
       
   144 // Close only closes the local array, while Reset resets the active array (may be external)
       
   145 inline void CSurfaceUtility::RHeapSurfaceArray::Reset()
       
   146 	{
       
   147 	iUseArray->Reset();
       
   148 	}
       
   149 
       
   150 void CSurfaceUtility::RHeapSurfaceArray::AppendL(const TSurfaceId &anEntry)
       
   151 	{
       
   152 	iUseArray->AppendL(anEntry);
       
   153 	}
       
   154 
       
   155 TInt CSurfaceUtility::RHeapSurfaceArray::Find(const TSurfaceId &anEntry) const
       
   156 	{
       
   157 	return iUseArray->Find(anEntry);
       
   158 	}
       
   159 
       
   160 void CSurfaceUtility::RHeapSurfaceArray::Remove(TInt anIndex)
       
   161 	{
       
   162 	iUseArray->Remove(anIndex);
       
   163 	}
       
   164 
       
   165 /**
       
   166 Cleanup stack helper object, holding references to both utility and surface, so
       
   167 that the standard Close() semantics can be used.
       
   168 */
       
   169 class TSurfaceCleanup
       
   170 	{
       
   171 public:
       
   172 	TSurfaceCleanup(CSurfaceUtility& aUtility, TSurfaceId& aSurface)
       
   173 		: iUtility(aUtility), iSurface(aSurface)
       
   174 		{}
       
   175 	void Close()
       
   176 		{
       
   177 		// Removes the surface from the list of surfaces to clean up, and closes
       
   178 		// the surface reference.
       
   179 		iUtility.DestroySurface(iSurface);
       
   180 		}
       
   181 private:
       
   182 	CSurfaceUtility& iUtility;
       
   183 	TSurfaceId& iSurface;
       
   184 	};
       
   185 
       
   186 /**
       
   187 Get the size of a surface.
       
   188 
       
   189 @param aSurface The surface to get the size for.
       
   190 @return The size in pixels, or empty on failure.
       
   191 */
       
   192 TSize CSurfaceUtility::SurfaceSize(const TSurfaceId& aSurface)
       
   193 	{
       
   194 	RSurfaceManager::TInfoBuf infoBuf;
       
   195 	RSurfaceManager::TSurfaceInfoV01& info = infoBuf();
       
   196 
       
   197 	if (iManager.SurfaceInfo(aSurface, infoBuf) == KErrNone)
       
   198 		{
       
   199 		return info.iSize;
       
   200 		}
       
   201 
       
   202 	return TSize();
       
   203 	}
       
   204 
       
   205 /**
       
   206 Create a surface using the surface manager.
       
   207 
       
   208 Stores the ID for tear down, as well as returning it.
       
   209 
       
   210 @param aSize Dimensions of the surface.
       
   211 @param aPixelFormat	UID of the pixel format.
       
   212 @param aStride	Stride value for the surface (usually bytes per pixel * width)
       
   213 @param aContiguous  Contiguous flag for creating surfaces
       
   214 @param aBuffers Number of buffers in the surface
       
   215 @leave May leave due to lack of memory.
       
   216 @return New surface's ID.
       
   217 */
       
   218 TSurfaceId CSurfaceUtility::CreateSurfaceL(const TSize& aSize, TUidPixelFormat aPixelFormat, TInt aStride, TBool aContiguous, TInt aBuffers)
       
   219 	{
       
   220 	RSurfaceManager::TSurfaceCreationAttributesBuf bf;
       
   221 	RSurfaceManager::TSurfaceCreationAttributes& b = bf();
       
   222 	if (aStride<aSize.iWidth*BytesPerPixelL(aPixelFormat))
       
   223 	    {
       
   224 	    User::Leave(KErrOverflow);
       
   225 	    }
       
   226 	b.iSize.iWidth = aSize.iWidth;
       
   227 	b.iSize.iHeight = aSize.iHeight;
       
   228 	b.iBuffers = aBuffers;				// number of buffers in the surface
       
   229 	b.iPixelFormat = aPixelFormat;
       
   230 	b.iStride = aStride;		// Number of bytes between start of one line and start of next
       
   231 	b.iOffsetToFirstBuffer = 0;	// way of reserving space before the surface pixel data
       
   232 	b.iAlignment = 4;			// alignment, 1,2,4,8 byte aligned
       
   233 	b.iContiguous = aContiguous;
       
   234 	b.iMappable = ETrue;
       
   235 
       
   236 	TSurfaceId surface = TSurfaceId::CreateNullId();
       
   237 
       
   238 	User::LeaveIfError(iManager.CreateSurface(bf, surface));
       
   239 	iSurfaces.AppendL(surface);
       
   240 	return surface;
       
   241 	}
       
   242 
       
   243 /**
       
   244 A helper function that returns the bytes per pixel for a given pixel format uid
       
   245 
       
   246 @param aPixelFormat Pixel format UID to convert
       
   247 @return The bytes per pixel
       
   248 */
       
   249 TInt CSurfaceUtility::BytesPerPixelL(TUidPixelFormat aPixelFormat)
       
   250 	{
       
   251 	TInt bytesPerPixel = 0;
       
   252 	switch (aPixelFormat)
       
   253 		{
       
   254 		case EUidPixelFormatXRGB_8888:
       
   255 		case EUidPixelFormatARGB_8888:
       
   256 		case EUidPixelFormatARGB_8888_PRE:
       
   257 			{
       
   258 			bytesPerPixel = 4;
       
   259 			break;
       
   260 			}
       
   261 		case EUidPixelFormatXRGB_4444:
       
   262 		case EUidPixelFormatARGB_4444:
       
   263 		case EUidPixelFormatRGB_565:
       
   264 			{
       
   265 			bytesPerPixel = 2;
       
   266 			break;
       
   267 			}
       
   268 		default:
       
   269 			{
       
   270 			User::Leave(KErrNotSupported);
       
   271 			break;
       
   272 			}
       
   273 		}
       
   274 	return bytesPerPixel;
       
   275 	}
       
   276 
       
   277 /**
       
   278 Fill buffer 0 of the given surface with a color.
       
   279 
       
   280 @param aSurface	The surface to be filled.
       
   281 @param aColor	The color to fill it with.
       
   282 */
       
   283 void CSurfaceUtility::FillSurfaceL(TSurfaceId& aSurface, const TRgb& aColor)
       
   284 	{
       
   285     FillSurfaceL(aSurface, 0, aColor);
       
   286 	}
       
   287 
       
   288 /**
       
   289 Fill a specified buffer number of the given surface with a color.
       
   290 
       
   291 @param aSurface	The surface to be filled.
       
   292 @param aBuffer 	The buffer to fill.
       
   293 @param aColor	The color to fill it with.
       
   294 */
       
   295 void CSurfaceUtility::FillSurfaceL(TSurfaceId& aSurface, TInt aBuffer, const TRgb& aColor)
       
   296 	{
       
   297 	RSurfaceManager::TInfoBuf infoBuf;
       
   298 	RSurfaceManager::TSurfaceInfoV01& info = infoBuf();
       
   299 
       
   300 	User::LeaveIfError(iManager.SurfaceInfo(aSurface, infoBuf));
       
   301 	TUint32 color = 0;
       
   302 	TBool use16 = EFalse;
       
   303 	TInt numBuffers = info.iBuffers;
       
   304 	if (aBuffer < 0 || aBuffer >= numBuffers)
       
   305 		{
       
   306 		User::Leave(KErrArgument);
       
   307 		}
       
   308 
       
   309 	if (info.iSize.iHeight<0 || info.iSize.iWidth<0 || info.iStride<0)
       
   310 		{
       
   311 		User::Leave(KErrCorrupt);
       
   312 		}
       
   313 	if (info.iSize.iHeight==0 || info.iSize.iWidth==0 || info.iStride==0)
       
   314 		{
       
   315 		User::Leave(KErrNotReady);
       
   316 		}
       
   317 
       
   318 	switch (info.iPixelFormat)
       
   319 		{
       
   320 		case EUidPixelFormatXRGB_8888:
       
   321 			{
       
   322 			color = aColor.Color16MU();
       
   323 			break;
       
   324 			}
       
   325 		case EUidPixelFormatARGB_8888:
       
   326 			{
       
   327 			color = aColor.Color16MA();
       
   328 			break;
       
   329 			}
       
   330 		case EUidPixelFormatARGB_8888_PRE:
       
   331 			{
       
   332 			color = aColor.Color16MAP();
       
   333 			break;
       
   334 			}
       
   335 		case EUidPixelFormatXRGB_4444:
       
   336 		case EUidPixelFormatARGB_4444:
       
   337 			{
       
   338 			color = aColor.Color4K();
       
   339 			use16 = ETrue;
       
   340 			break;
       
   341 			}
       
   342 		case EUidPixelFormatRGB_565:
       
   343 			{
       
   344 			color = aColor.Color64K();
       
   345 			use16 = ETrue;
       
   346 			break;
       
   347 			}
       
   348 		default:
       
   349 			{
       
   350 			User::Leave(KErrNotSupported);
       
   351 			break;
       
   352 			}
       
   353 		}
       
   354 
       
   355 	RChunk chunk;
       
   356 	User::LeaveIfError(iManager.MapSurface(aSurface, chunk));
       
   357 	CleanupClosePushL(chunk);
       
   358 
       
   359 	TInt offsetToBuffer;
       
   360 	User::LeaveIfError(iManager.GetBufferOffset(aSurface, aBuffer, offsetToBuffer));
       
   361 	TUint8* surfacePtr = chunk.Base() + offsetToBuffer;
       
   362 	TUint8* linePtr = surfacePtr;
       
   363 
       
   364 	if (use16)
       
   365 		{
       
   366 		if ( info.iSize.iWidth*2>info.iStride)
       
   367 			{
       
   368 			User::Leave(KErrOverflow);
       
   369 			}
       
   370 		TUint16* ptr = reinterpret_cast<TUint16*>(surfacePtr);
       
   371 
       
   372 		// Fill first line
       
   373 		for (TInt xx = 0; xx < info.iSize.iWidth; xx++)
       
   374 			{
       
   375 			ptr[xx] = (TUint16)color;
       
   376 			}
       
   377 		}
       
   378 	else
       
   379 		{
       
   380 		if ( info.iSize.iWidth*4>info.iStride)
       
   381 			{
       
   382 			User::Leave(KErrOverflow);
       
   383 			}
       
   384 		TUint32* ptr = reinterpret_cast<TUint32*>(surfacePtr);
       
   385 
       
   386 		// Fill first line
       
   387 		for (TInt xx = 0; xx < info.iSize.iWidth; xx++)
       
   388 			{
       
   389 			ptr[xx] = color;
       
   390 			}
       
   391 		}
       
   392 
       
   393 	// Now copy that to the other lines
       
   394 	for (TInt yy = 1; yy < info.iSize.iHeight; yy++)
       
   395 		{
       
   396 		linePtr += info.iStride;
       
   397 		Mem::Copy(linePtr, surfacePtr, info.iSize.iWidth * BytesPerPixelL(info.iPixelFormat));
       
   398 		}
       
   399 	
       
   400 	CleanupStack::PopAndDestroy(/* chunk */);
       
   401 	}
       
   402 
       
   403 /**
       
   404 Destroy a surface.
       
   405 
       
   406 As well as destroying the surface, it is removed from the set held for
       
   407 destruction during tear down.
       
   408 
       
   409 @param aSurface	The surface to be destroyed.
       
   410 */
       
   411 void CSurfaceUtility::DestroySurface(TSurfaceId& aSurface)
       
   412 	{
       
   413 	TInt index = iSurfaces.Find(aSurface);
       
   414 	
       
   415 	if (index != KErrNotFound)
       
   416 		{
       
   417 		iSurfaces.Remove(index);
       
   418 		}
       
   419 
       
   420 	TInt err = iManager.CloseSurface(aSurface);
       
   421 	if (err!=KErrNone)
       
   422 		LOG(("Error closing surfaces: 0x%X\n", err));
       
   423 	}
       
   424 
       
   425 /**
       
   426 Get surface header information
       
   427 
       
   428 @param aSurface A surface to get the header info from.
       
   429 @param aInfo Returned package info of the surface header.
       
   430 
       
   431 @return KErrNone if successful, KErrArgument if the surface ID does not refer to a surface,
       
   432 KErrAccessDenied if the surface is not open in the current process, otherwise a system wide
       
   433 error code.
       
   434  */
       
   435 TInt CSurfaceUtility::GetHeader(const TSurfaceId& aSurface, RSurfaceManager::TInfoBuf& aInfo) 
       
   436     {
       
   437     return iManager.SurfaceInfo(aSurface, aInfo);
       
   438     }
       
   439 
       
   440 /**
       
   441 Get buffer pointer to a surface
       
   442 
       
   443 @param aSurface Surface of the buffer pointer.
       
   444 @param aNumOfBuffer A number of buffer.
       
   445 @param aChunk A chunk of memory.
       
   446 
       
   447 @return A buffer pointer of the surface.
       
   448  */
       
   449 TUint8* CSurfaceUtility::GetBufferPointerL(const TSurfaceId& aSurface, TInt aNumOfBuffer, RChunk& aChunk) 
       
   450     {
       
   451     TInt offsetToBuffer;
       
   452     User::LeaveIfError(iManager.MapSurface(aSurface, aChunk));
       
   453     User::LeaveIfError(iManager.GetBufferOffset(aSurface, aNumOfBuffer, offsetToBuffer));
       
   454     TUint8* surfacePtr = aChunk.Base() + offsetToBuffer;
       
   455     return surfacePtr;
       
   456     }
       
   457 
       
   458 /**
       
   459 Get pixel color at a position.
       
   460 
       
   461 @param aInfo Package info of a surface.
       
   462 @param aPixelData Surface buffer pointer.
       
   463 @param aPosition Position of the pixel.
       
   464 
       
   465 @return Color of the pixel position.
       
   466 */
       
   467 TRgb CSurfaceUtility::GetPixelL(RSurfaceManager::TInfoBuf& aInfo, TAny* aPixelData, TPoint aPosition) 
       
   468     {
       
   469     RSurfaceManager::TSurfaceInfoV01& info = aInfo();
       
   470     TInt stride = info.iStride;
       
   471     TUidPixelFormat pixelFormat = info.iPixelFormat;
       
   472     TInt bytesPerPixel = BytesPerPixelL(pixelFormat);
       
   473     TInt pixelStride = stride / bytesPerPixel;
       
   474     TUint pixel = aPosition.iY * pixelStride + aPosition.iX;
       
   475     TUint* pixels = reinterpret_cast< TUint* >( aPixelData );
       
   476     TRgb colour;
       
   477     colour.SetInternal(pixels[ pixel ]);
       
   478     return colour;
       
   479     }
       
   480 
       
   481 /**
       
   482 Check pixel color within a rectangle is as expected.
       
   483 It checks every color channel of every pixel within the rectangle.
       
   484 
       
   485 @param aSurface The surface to be checked.
       
   486 @param aRect The rectangle for pixel checking.
       
   487 @param aNumOfBuffer Number of buffer.
       
   488 @param aExpectedColor The expected color.
       
   489 @param aTolerance A tolerance value.
       
   490 
       
   491 @return EFalse if a color channel of a pixel is outside the tolerance range. 
       
   492         ETrue if all pixel colors are within the tolerance range.
       
   493 */
       
   494 TBool CSurfaceUtility::CheckRectColor(const TSurfaceId& aSurface, TRect& aRect, TInt aNumOfBuffer, const TRgb& aExpectedColor, TInt aTolerance) 
       
   495     {
       
   496     RSurfaceManager::TInfoBuf infoBuf;
       
   497     RSurfaceManager::TSurfaceInfoV01& info = infoBuf();
       
   498     TInt error = GetHeader(aSurface, infoBuf);
       
   499     if (error != KErrNone)
       
   500     	{
       
   501 		RDebug::Printf("Line %d GetHeader failed",__LINE__);
       
   502 		return EFalse;
       
   503     	}
       
   504 
       
   505     RChunk chunk;
       
   506     TUint8* surfacePtr = NULL;
       
   507     TRAP_IGNORE(surfacePtr = GetBufferPointerL(aSurface, aNumOfBuffer, chunk));
       
   508     if (!surfacePtr)
       
   509     	{
       
   510 		RDebug::Printf("Line %d GetBufferPointerL failed",__LINE__);
       
   511 		return EFalse;
       
   512     	}
       
   513     
       
   514     TRgb color;
       
   515     // Check every colour channel of every pixel is within the tolerance
       
   516     for (TInt ii = aRect.iTl.iX; ii < aRect.iBr.iX; ++ii)
       
   517         {
       
   518         for (TInt jj = aRect.iTl.iY; jj < aRect.iBr.iY; ++jj)
       
   519             {
       
   520             color = GetPixelL(infoBuf, surfacePtr, TPoint(ii, jj));      
       
   521             TBool checkR = (color.Red() <= (aExpectedColor.Red() + aTolerance) && color.Red() >= (aExpectedColor.Red() - aTolerance));
       
   522             TBool checkG = (color.Green() <= (aExpectedColor.Green() + aTolerance) && color.Green() >= (aExpectedColor.Green() - aTolerance));
       
   523             TBool checkB = (color.Blue() <= (aExpectedColor.Blue() + aTolerance) && color.Blue() >= (aExpectedColor.Blue() - aTolerance));
       
   524             if (!checkR || !checkG || !checkB)
       
   525                 {
       
   526                 RDebug::Printf("At x=%d y=%d CheckRectColor has failed:",ii,jj);
       
   527                 RDebug::Printf("Expected Red %d - Actual Red %d",aExpectedColor.Red(),color.Red());
       
   528                 RDebug::Printf("Expected Green %d - Actual Green %d",aExpectedColor.Green(),color.Green());
       
   529                 RDebug::Printf("Expected Blue %d - Actual Blue %d",aExpectedColor.Blue(),color.Blue());
       
   530                 return EFalse;            
       
   531                 }               
       
   532             }
       
   533         }
       
   534     return ETrue;
       
   535     }
       
   536 
       
   537 /**
       
   538 Save on screen image to a .tga file
       
   539 
       
   540 @param aSurface A surface to be saved
       
   541 @param aBufferNumber The surface's buffer number
       
   542 @param aDestination The path and name of the tga to save eg c:\\test\\img\\image1.tga
       
   543 @return ETrue on successful calls
       
   544         Fails if GetBufferPointerL returns NULL pointer
       
   545  */
       
   546 TBool CSurfaceUtility::SaveResultImageTGAL(const TSurfaceId& aSurface, TInt aBufferNumber, TDesC& aDestination)
       
   547     {
       
   548     RSurfaceManager::TInfoBuf infoBuf;
       
   549     RSurfaceManager::TSurfaceInfoV01& info = infoBuf();
       
   550     User::LeaveIfError(GetHeader(aSurface, infoBuf));
       
   551     TInt stride = info.iStride;
       
   552     TSize surfaceSize = info.iSize;
       
   553     TUidPixelFormat pixelFormat = info.iPixelFormat;
       
   554     TInt bytesPerPixel = BytesPerPixelL(pixelFormat);
       
   555     TInt widthInBytes = surfaceSize.iWidth * bytesPerPixel;
       
   556     
       
   557     RFs fs;
       
   558     User::LeaveIfError(fs.Connect());
       
   559     CleanupClosePushL(fs); 
       
   560         
       
   561     // Create image file
       
   562     RFileWriteStream fstream;
       
   563     User::LeaveIfError(fstream.Replace(fs, aDestination, EFileShareAny|EFileWrite));
       
   564     CleanupClosePushL(fstream); 
       
   565     
       
   566     // Write header
       
   567     fstream.WriteUint8L(0);                 // ID Length
       
   568     fstream.WriteUint8L(0);                 // Color map type
       
   569     fstream.WriteUint8L(2);                 // Image type - Uncompressed, True-color Image
       
   570     fstream.WriteUint32L(0);                // Color map specification 5 bytes
       
   571     fstream.WriteUint8L(0);                 // Color map specification
       
   572     fstream.WriteUint32L(0);                // Image specification - origin of image
       
   573     fstream.WriteUint16L(static_cast<TUint16>(surfaceSize.iWidth));      // Image specification - Image width
       
   574     fstream.WriteUint16L(static_cast<TUint16>(surfaceSize.iHeight));     // Image specification - Image height
       
   575     fstream.WriteUint8L(32);                // Image specification - Pixel Depth (bits per pixel)
       
   576     fstream.WriteUint8L(1 << 5);            // Image specification - Image Descriptor, Screen destination of first pixel is top left 
       
   577 
       
   578     RChunk chunk;
       
   579     TUint8* surfacePtr = GetBufferPointerL(aSurface, aBufferNumber, chunk);
       
   580     if(surfacePtr == NULL)
       
   581         {
       
   582         CleanupStack::PopAndDestroy(2); 
       
   583         return EFalse;
       
   584         }
       
   585     
       
   586     // Write image line by line
       
   587     for(TInt ii = 0; ii < surfaceSize.iHeight; ++ii)
       
   588         {
       
   589         fstream.WriteL(surfacePtr, widthInBytes); 
       
   590         surfacePtr += stride;
       
   591         }
       
   592 
       
   593     fstream.CommitL();
       
   594     chunk.Close();
       
   595     CleanupStack::PopAndDestroy(2); 
       
   596     
       
   597     return ETrue;
       
   598     }
       
   599 
       
   600 /**
       
   601 Create directory for images to be saved
       
   602 
       
   603 @param aDir Directory for images to be saved
       
   604 @return ETrue on success
       
   605  */
       
   606 TBool CSurfaceUtility::CreateImagePath(TDesC& aDir)
       
   607     {
       
   608     RFs fs;
       
   609     TInt err = fs.Connect();
       
   610     if (err == KErrNone)
       
   611         {
       
   612         err = fs.MkDirAll(aDir);
       
   613         if (err == KErrAlreadyExists)
       
   614             {
       
   615             err = KErrNone;
       
   616             }
       
   617         fs.Close();
       
   618         }
       
   619     return (err == KErrNone);
       
   620     }
       
   621     
       
   622 /**
       
   623 Submit an update to a surface to the update server.
       
   624 
       
   625 @param aSurface	The surface which has been updated.
       
   626 @param aRegion	The area of the surface affected, or NULL for all of it.
       
   627 */
       
   628 TInt CSurfaceUtility::SubmitUpdate(const TSurfaceId& aSurface,TInt aBufferNumber, const TRegion* aRegion)
       
   629 	{
       
   630 	if (!iSurfaceUpdateSession.Handle())
       
   631 	    {
       
   632 	    iSurfaceUpdateSession.Connect();
       
   633 	    }
       
   634     if (!iSurfaceUpdateSession.Handle())
       
   635         {
       
   636         LOG(("Error - SUS client not started!"));
       
   637         return KErrNotReady;
       
   638         }
       
   639     else
       
   640         {
       
   641         TInt err =iSurfaceUpdateSession.SubmitUpdate(KAllScreens, aSurface, aBufferNumber, aRegion); 
       
   642         if (err!=KErrNone)
       
   643             LOG(("Error submitting update: 0x%X\n", err));
       
   644         return err;
       
   645         }
       
   646 	}
       
   647 
       
   648 void CSurfaceUtility::NotifyWhenDisplayed(TRequestStatus& aStatusDisplayed, TTimeStamp& aTimeStamp)
       
   649     {
       
   650     iSurfaceUpdateSession.NotifyWhenDisplayed(aStatusDisplayed, aTimeStamp);
       
   651     }
       
   652 
       
   653 void CSurfaceUtility::NotifyWhenDisplayedXTimes(TInt aCount, TRequestStatus& aStatusDisplayedX)
       
   654     {
       
   655     iSurfaceUpdateSession.NotifyWhenDisplayedXTimes(aCount, aStatusDisplayedX);
       
   656     }
       
   657 
       
   658 void CSurfaceUtility::NotifyWhenAvailable(TRequestStatus& aStatusAvailable)
       
   659     {
       
   660     iSurfaceUpdateSession.NotifyWhenAvailable(aStatusAvailable);
       
   661     }
       
   662 
       
   663 SymbianStreamType CSurfaceUtility::GetOnScreenStream(WFCDevice aDev, WFCContext aContext)
       
   664     {
       
   665     return reinterpret_cast<SymbianStreamType>(wfcGetOnScreenStream(aDev, aContext));
       
   666     }
       
   667 
       
   668 
       
   669