--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graphicstest/uibench/s60/src/surfaceutility.cpp Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,1784 @@
+// 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"
+#include <BitmapTransforms.h>
+
+//_LIT(KFileName,"surfacemanager");
+
+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();
+
+ // the following call is needed because of a bug in CImageDecoder that
+ // leaks heap memory
+ REComSession::FinalClose();
+ }
+
+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());
+
+ // Copy the data from the bitmap into the surface.
+ TPoint start;
+ 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(chunk.Base() + 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
+
+ // Copy the data from the bitmap into the surface.
+ TPoint start;
+ 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(chunk.Base() + 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, const 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 = SurfaceSize(aSurface);
+ 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());
+
+ // Copy the data from the bitmap into the surface.
+ TPoint start;
+ 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(chunk.Base() + start.iY * stride, stride);
+ bitmap->GetScanLine(ptr, start, size.iWidth, bmpFormat);
+ }
+
+ CleanupStack::PopAndDestroy(/* chunk */);
+ CleanupStack::PopAndDestroy(bitmap);
+ CleanupStack::PopAndDestroy(decoder);
+ CleanupStack::PopAndDestroy(/* fs */);
+ }
+
+/**
+Copy the bitmap from a file to a surface scaling the original image to cover the entire surface.
+
+@param aFileName The name of the image file.
+@param aSurface Filled with the surface ID for the surface containing the pixels.
+*/
+void CSurfaceUtility::ScaleBitmapFromFileToSurfaceL(const TDesC& aFileName, const 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 = SurfaceSize(aSurface);
+ 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(info.iOverallSizeInPixels, info.iFrameDisplayMode));
+
+ RChunk chunk;
+ User::LeaveIfError(iManager.MapSurface(aSurface, chunk));
+ CleanupClosePushL(chunk);
+ TUint8* surfacePixelData = chunk.Base() + PixelDataOffet(aSurface);
+
+ // Convert the image file into a Symbian bitmap
+ // CImageDecoder::EOptionAlwaysThread setting above avoids need for Active Object
+ TRequestStatus status;
+ decoder->Convert(&status, *bitmap);
+ User::WaitForRequest(status);
+ User::LeaveIfError(status.Int());
+
+ // scale to fit surface
+ CBitmapScaler* scaler = CBitmapScaler::NewL();
+ CleanupStack::PushL(scaler);
+ scaler->SetQualityAlgorithm(CBitmapScaler::EMaximumQuality);
+
+ CActiveListener* activeListener = CActiveListener::NewLC();
+ activeListener->Initialize();
+ scaler->Scale(&activeListener->iStatus, *bitmap, size, EFalse);
+ CActiveScheduler::Start();
+
+ User::LeaveIfError(activeListener->iStatus.Int());
+
+ // Copy the data from the bitmap into the surface.
+ TPoint start;
+ 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(surfacePixelData + start.iY * stride, stride);
+ bitmap->GetScanLine(ptr, start, size.iWidth, EColor16MA);
+ }
+ CleanupStack::PopAndDestroy(activeListener);
+ CleanupStack::PopAndDestroy(scaler);
+ 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();
+ }
+
+/**
+Get the offset into the chunk of the start of pixel data.
+
+@param aSurface The surface to get the size for.
+@return The offset bytes, or empty on failure.
+*/
+TInt CSurfaceUtility::PixelDataOffet(const TSurfaceId& aSurface)
+ {
+ TInt offsetToFirstBuffer = 0;
+ iManager.GetBufferOffset(aSurface, 0, offsetToFirstBuffer);
+
+ return offsetToFirstBuffer;
+ }
+
+
+/**
+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;
+
+ TSurfaceId surface = TSurfaceId::CreateNullId();
+
+ User::LeaveIfError(iManager.CreateSurface(bf, surface));
+ iSurfaces.AppendL(surface);
+ return surface;
+ }
+
+
+/**
+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));
+
+ TUint8* surfacePtr = chunk.Base();
+ 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::Move(linePtr, surfacePtr, info.iStride);
+ }
+
+ chunk.Close();
+
+ TInt err = iSurfaceUpdateSession.SubmitUpdate(0, aSurface, 0, NULL);
+ if (err!=KErrNone)
+ LOG(("Error submitting update: 0x%X\n", err));
+ }
+
+/**
+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, TPoint& aStartPos, 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));
+
+ TUint8* surfacePtr = chunk.Base();
+
+ // 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++;
+ }
+ }
+
+ chunk.Close();
+
+ 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, TPoint& aStartPos, 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));
+
+ TUint8* surfacePtr = chunk.Base();
+
+ // 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++;
+ }
+ }
+
+ chunk.Close();
+
+ }
+
+/**
+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));
+
+ TUint8* surfacePtr = chunk.Base();
+ 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::Move(linePtr, surfacePtr + info.iStride, info.iStride);
+ }
+ else
+ {
+ // Copy first line
+ Mem::Move(linePtr, surfacePtr, info.iStride);
+ }
+ }
+ chunk.Close();
+
+ TInt err =iSurfaceUpdateSession.SubmitUpdate(0, aSurface, 0, NULL);
+ if (err!=KErrNone)
+ LOG(("Error submitting update: 0x%X\n", err));
+
+ }
+
+
+/**
+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));
+ TUint8* surfacePtr = chunk.Base();
+ 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);
+ }
+
+ chunk.Close();
+
+ iSurfaceUpdateSession.SubmitUpdate(0, aSurface, 0, NULL);
+ }
+/**
+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));
+
+ TUint8* surfacePtr = chunk.Base();
+ 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));
+ TUint8* surfacePtr = chunk.Base();
+ 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);
+
+ // Copy the data from the bitmap into the surface.
+ TPoint start;
+ 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(chunk.Base() + 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 */);
+ }
+
+/**
+CActiveListener factory function
+@return A CActiveListener object
+*/
+CActiveListener* CActiveListener::NewLC()
+ {
+ CActiveListener* self = new(ELeave) CActiveListener();
+ CleanupStack::PushL(self);
+ return self;
+ }
+
+/**
+Constructor for class CActiveListener
+*/
+CActiveListener::CActiveListener() : CActive(EPriorityLow)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+/**
+Destructor
+*/
+CActiveListener::~CActiveListener()
+ {
+ }
+
+/**
+Handles the request.
+This function is derived from CActive
+*/
+void CActiveListener::RunL()
+ {
+ CActiveScheduler::Stop();
+ }
+
+/**
+Cancels the outstanding request.
+This function is derived from CActive
+*/
+void CActiveListener::DoCancel()
+ {
+ }
+
+/**
+Initializes the CActiveListener
+*/
+void CActiveListener::Initialize()
+ {
+ iStatus = KRequestPending;
+ SetActive();
+ }
+
+/**
+Check that the request has been cancelled.
+@return A boolean indicating whether the request has been cancelled or not
+*/
+TBool CActiveListener::IsRequestCancelled()
+ {
+ return (iStatus == KErrCancel);
+ }
+
+/**
+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;
+ }
+