Update contrib.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
21 #include <imageconversion.h>
24 #include "surfaceutility.h"
30 WFC_API_CALL WFCNativeStreamType WFC_APIENTRY
31 extwfcGetOnScreenStream(WFCDevice dev, WFCContext context) WFC_APIEXIT;
37 CSurfaceUtility::CSurfaceUtility()
42 CSurfaceUtility* CSurfaceUtility::NewL()
44 CSurfaceUtility* utility = new (ELeave)CSurfaceUtility();
45 CleanupStack::PushL(utility);
46 utility->ConstructL();
47 CleanupStack::Pop(utility);
51 void CSurfaceUtility::ConstructL()
53 TInt r = iManager.Open();
56 LOG(("Surface manager failed to open: %d", r));
60 r = iSurfaceUpdateSession.Connect();
63 LOG(("Failed to connect to update server: %d", r));
68 CSurfaceUtility::~CSurfaceUtility()
76 iSurfaceUpdateSession.Close();
79 TBool CSurfaceUtility::DestroyAll()
82 TInt jj = iSurfaces.Count() - 1;
87 err = iManager.CloseSurface(iSurfaces[jj]);
90 LOG(("Error closing surface: 0x%X\n", err));
93 err = iManager.GetBufferOffset(iSurfaces[jj],0,offset);
96 LOG(("Error: closed surface still accessible: index %i surface %08X %08X %08X %08X\n", jj, iSurfaces[jj]));
103 /***************************************
104 * The aim of the THeapSurfaceArray is to locally switch in the specified heap for any array operation
105 ***************************************/
107 CSurfaceUtility::RHeapSurfaceArray::RHeapSurfaceArray(RHeapSurfaceArray* aUseExternalArray)
108 : iUseArray(aUseExternalArray?aUseExternalArray->iUseArray:&this->iLocalArray),
109 iExternalHeapRef(aUseExternalArray?aUseExternalArray->iExternalHeapRef:User::Heap())
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 ************************************/
121 // PopAndDestroy method to restore the heap
122 /*static*/ void CSurfaceUtility::RHeapSurfaceArray::PopHeap(void* aHeapPtr)
124 RHeap* heapPtr=(RHeap*)aHeapPtr;
125 User::SwitchHeap(heapPtr);
128 TSurfaceId& CSurfaceUtility::RHeapSurfaceArray::operator[](TUint aIndex)
130 return iUseArray->operator[](aIndex);
133 // Close only closes the local array, while Reset resets the active array (may be external)
134 void CSurfaceUtility::RHeapSurfaceArray::Close()
139 TInt CSurfaceUtility::RHeapSurfaceArray::Count() const
141 return iUseArray->Count();
144 // Close only closes the local array, while Reset resets the active array (may be external)
145 inline void CSurfaceUtility::RHeapSurfaceArray::Reset()
150 void CSurfaceUtility::RHeapSurfaceArray::AppendL(const TSurfaceId &anEntry)
152 iUseArray->AppendL(anEntry);
155 TInt CSurfaceUtility::RHeapSurfaceArray::Find(const TSurfaceId &anEntry) const
157 return iUseArray->Find(anEntry);
160 void CSurfaceUtility::RHeapSurfaceArray::Remove(TInt anIndex)
162 iUseArray->Remove(anIndex);
166 Cleanup stack helper object, holding references to both utility and surface, so
167 that the standard Close() semantics can be used.
169 class TSurfaceCleanup
172 TSurfaceCleanup(CSurfaceUtility& aUtility, TSurfaceId& aSurface)
173 : iUtility(aUtility), iSurface(aSurface)
177 // Removes the surface from the list of surfaces to clean up, and closes
178 // the surface reference.
179 iUtility.DestroySurface(iSurface);
182 CSurfaceUtility& iUtility;
183 TSurfaceId& iSurface;
187 Get the size of a surface.
189 @param aSurface The surface to get the size for.
190 @return The size in pixels, or empty on failure.
192 TSize CSurfaceUtility::SurfaceSize(const TSurfaceId& aSurface)
194 RSurfaceManager::TInfoBuf infoBuf;
195 RSurfaceManager::TSurfaceInfoV01& info = infoBuf();
197 if (iManager.SurfaceInfo(aSurface, infoBuf) == KErrNone)
206 Create a surface using the surface manager.
208 Stores the ID for tear down, as well as returning it.
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.
218 TSurfaceId CSurfaceUtility::CreateSurfaceL(const TSize& aSize, TUidPixelFormat aPixelFormat, TInt aStride, TBool aContiguous, TInt aBuffers)
220 RSurfaceManager::TSurfaceCreationAttributesBuf bf;
221 RSurfaceManager::TSurfaceCreationAttributes& b = bf();
222 if (aStride<aSize.iWidth*BytesPerPixelL(aPixelFormat))
224 User::Leave(KErrOverflow);
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;
236 TSurfaceId surface = TSurfaceId::CreateNullId();
238 User::LeaveIfError(iManager.CreateSurface(bf, surface));
239 iSurfaces.AppendL(surface);
244 A helper function that returns the bytes per pixel for a given pixel format uid
246 @param aPixelFormat Pixel format UID to convert
247 @return The bytes per pixel
249 TInt CSurfaceUtility::BytesPerPixelL(TUidPixelFormat aPixelFormat)
251 TInt bytesPerPixel = 0;
252 switch (aPixelFormat)
254 case EUidPixelFormatXRGB_8888:
255 case EUidPixelFormatARGB_8888:
256 case EUidPixelFormatARGB_8888_PRE:
261 case EUidPixelFormatXRGB_4444:
262 case EUidPixelFormatARGB_4444:
263 case EUidPixelFormatRGB_565:
270 User::Leave(KErrNotSupported);
274 return bytesPerPixel;
278 Fill buffer 0 of the given surface with a color.
280 @param aSurface The surface to be filled.
281 @param aColor The color to fill it with.
283 void CSurfaceUtility::FillSurfaceL(TSurfaceId& aSurface, const TRgb& aColor)
285 FillSurfaceL(aSurface, 0, aColor);
289 Fill a specified buffer number of the given surface with a color.
291 @param aSurface The surface to be filled.
292 @param aBuffer The buffer to fill.
293 @param aColor The color to fill it with.
295 void CSurfaceUtility::FillSurfaceL(TSurfaceId& aSurface, TInt aBuffer, const TRgb& aColor)
297 RSurfaceManager::TInfoBuf infoBuf;
298 RSurfaceManager::TSurfaceInfoV01& info = infoBuf();
300 User::LeaveIfError(iManager.SurfaceInfo(aSurface, infoBuf));
302 TBool use16 = EFalse;
303 TInt numBuffers = info.iBuffers;
304 if (aBuffer < 0 || aBuffer >= numBuffers)
306 User::Leave(KErrArgument);
309 if (info.iSize.iHeight<0 || info.iSize.iWidth<0 || info.iStride<0)
311 User::Leave(KErrCorrupt);
313 if (info.iSize.iHeight==0 || info.iSize.iWidth==0 || info.iStride==0)
315 User::Leave(KErrNotReady);
318 switch (info.iPixelFormat)
320 case EUidPixelFormatXRGB_8888:
322 color = aColor.Color16MU();
325 case EUidPixelFormatARGB_8888:
327 color = aColor.Color16MA();
330 case EUidPixelFormatARGB_8888_PRE:
332 color = aColor.Color16MAP();
335 case EUidPixelFormatXRGB_4444:
336 case EUidPixelFormatARGB_4444:
338 color = aColor.Color4K();
342 case EUidPixelFormatRGB_565:
344 color = aColor.Color64K();
350 User::Leave(KErrNotSupported);
356 User::LeaveIfError(iManager.MapSurface(aSurface, chunk));
357 CleanupClosePushL(chunk);
360 User::LeaveIfError(iManager.GetBufferOffset(aSurface, aBuffer, offsetToBuffer));
361 TUint8* surfacePtr = chunk.Base() + offsetToBuffer;
362 TUint8* linePtr = surfacePtr;
366 if ( info.iSize.iWidth*2>info.iStride)
368 User::Leave(KErrOverflow);
370 TUint16* ptr = reinterpret_cast<TUint16*>(surfacePtr);
373 for (TInt xx = 0; xx < info.iSize.iWidth; xx++)
375 ptr[xx] = (TUint16)color;
380 if ( info.iSize.iWidth*4>info.iStride)
382 User::Leave(KErrOverflow);
384 TUint32* ptr = reinterpret_cast<TUint32*>(surfacePtr);
387 for (TInt xx = 0; xx < info.iSize.iWidth; xx++)
393 // Now copy that to the other lines
394 for (TInt yy = 1; yy < info.iSize.iHeight; yy++)
396 linePtr += info.iStride;
397 Mem::Copy(linePtr, surfacePtr, info.iSize.iWidth * BytesPerPixelL(info.iPixelFormat));
400 CleanupStack::PopAndDestroy(/* chunk */);
406 As well as destroying the surface, it is removed from the set held for
407 destruction during tear down.
409 @param aSurface The surface to be destroyed.
411 void CSurfaceUtility::DestroySurface(TSurfaceId& aSurface)
413 TInt index = iSurfaces.Find(aSurface);
415 if (index != KErrNotFound)
417 iSurfaces.Remove(index);
420 TInt err = iManager.CloseSurface(aSurface);
422 LOG(("Error closing surfaces: 0x%X\n", err));
426 Get surface header information
428 @param aSurface A surface to get the header info from.
429 @param aInfo Returned package info of the surface header.
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
435 TInt CSurfaceUtility::GetHeader(const TSurfaceId& aSurface, RSurfaceManager::TInfoBuf& aInfo)
437 return iManager.SurfaceInfo(aSurface, aInfo);
441 Get buffer pointer to a surface
443 @param aSurface Surface of the buffer pointer.
444 @param aNumOfBuffer A number of buffer.
445 @param aChunk A chunk of memory.
447 @return A buffer pointer of the surface.
449 TUint8* CSurfaceUtility::GetBufferPointerL(const TSurfaceId& aSurface, TInt aNumOfBuffer, RChunk& aChunk)
452 User::LeaveIfError(iManager.MapSurface(aSurface, aChunk));
453 User::LeaveIfError(iManager.GetBufferOffset(aSurface, aNumOfBuffer, offsetToBuffer));
454 TUint8* surfacePtr = aChunk.Base() + offsetToBuffer;
459 Get pixel color at a position.
461 @param aInfo Package info of a surface.
462 @param aPixelData Surface buffer pointer.
463 @param aPosition Position of the pixel.
465 @return Color of the pixel position.
467 TRgb CSurfaceUtility::GetPixelL(RSurfaceManager::TInfoBuf& aInfo, TAny* aPixelData, TPoint aPosition)
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 );
477 colour.SetInternal(pixels[ pixel ]);
482 Check pixel color within a rectangle is as expected.
483 It checks every color channel of every pixel within the rectangle.
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.
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.
494 TBool CSurfaceUtility::CheckRectColor(const TSurfaceId& aSurface, TRect& aRect, TInt aNumOfBuffer, const TRgb& aExpectedColor, TInt aTolerance)
496 RSurfaceManager::TInfoBuf infoBuf;
497 RSurfaceManager::TSurfaceInfoV01& info = infoBuf();
498 TInt error = GetHeader(aSurface, infoBuf);
499 if (error != KErrNone)
501 RDebug::Printf("Line %d GetHeader failed",__LINE__);
506 TUint8* surfacePtr = NULL;
507 TRAP_IGNORE(surfacePtr = GetBufferPointerL(aSurface, aNumOfBuffer, chunk));
510 RDebug::Printf("Line %d GetBufferPointerL failed",__LINE__);
515 // Check every colour channel of every pixel is within the tolerance
516 for (TInt ii = aRect.iTl.iX; ii < aRect.iBr.iX; ++ii)
518 for (TInt jj = aRect.iTl.iY; jj < aRect.iBr.iY; ++jj)
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)
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());
538 Save on screen image to a .tga file
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
546 TBool CSurfaceUtility::SaveResultImageTGAL(const TSurfaceId& aSurface, TInt aBufferNumber, TDesC& aDestination)
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;
558 User::LeaveIfError(fs.Connect());
559 CleanupClosePushL(fs);
562 RFileWriteStream fstream;
563 User::LeaveIfError(fstream.Replace(fs, aDestination, EFileShareAny|EFileWrite));
564 CleanupClosePushL(fstream);
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
579 TUint8* surfacePtr = GetBufferPointerL(aSurface, aBufferNumber, chunk);
580 if(surfacePtr == NULL)
582 CleanupStack::PopAndDestroy(2);
586 // Write image line by line
587 for(TInt ii = 0; ii < surfaceSize.iHeight; ++ii)
589 fstream.WriteL(surfacePtr, widthInBytes);
590 surfacePtr += stride;
595 CleanupStack::PopAndDestroy(2);
601 Create directory for images to be saved
603 @param aDir Directory for images to be saved
604 @return ETrue on success
606 TBool CSurfaceUtility::CreateImagePath(TDesC& aDir)
609 TInt err = fs.Connect();
612 err = fs.MkDirAll(aDir);
613 if (err == KErrAlreadyExists)
619 return (err == KErrNone);
623 Submit an update to a surface to the update server.
625 @param aSurface The surface which has been updated.
626 @param aRegion The area of the surface affected, or NULL for all of it.
628 TInt CSurfaceUtility::SubmitUpdate(const TSurfaceId& aSurface,TInt aBufferNumber, const TRegion* aRegion)
630 if (!iSurfaceUpdateSession.Handle())
632 iSurfaceUpdateSession.Connect();
634 if (!iSurfaceUpdateSession.Handle())
636 LOG(("Error - SUS client not started!"));
641 TInt err =iSurfaceUpdateSession.SubmitUpdate(KAllScreens, aSurface, aBufferNumber, aRegion);
643 LOG(("Error submitting update: 0x%X\n", err));
648 void CSurfaceUtility::NotifyWhenDisplayed(TRequestStatus& aStatusDisplayed, TTimeStamp& aTimeStamp)
650 iSurfaceUpdateSession.NotifyWhenDisplayed(aStatusDisplayed, aTimeStamp);
653 void CSurfaceUtility::NotifyWhenDisplayedXTimes(TInt aCount, TRequestStatus& aStatusDisplayedX)
655 iSurfaceUpdateSession.NotifyWhenDisplayedXTimes(aCount, aStatusDisplayedX);
658 void CSurfaceUtility::NotifyWhenAvailable(TRequestStatus& aStatusAvailable)
660 iSurfaceUpdateSession.NotifyWhenAvailable(aStatusAvailable);
663 SymbianStreamType CSurfaceUtility::GetOnScreenStream(WFCDevice aDev, WFCContext aContext)
665 return reinterpret_cast<SymbianStreamType>(wfcGetOnScreenStream(aDev, aContext));