diff -r 000000000000 -r bde4ae8d615e os/graphics/graphicstest/uibench/s60/src/surfaceutility.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/graphics/graphicstest/uibench/s60/src/surfaceutility.cpp Fri Jun 15 03:10:57 2012 +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 +#include +#include "surfaceutility.h" +#include + +//_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(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(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(KAllScreens, 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(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(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(surfacePtr); + + // Fill the rectangle + TInt yPos = aStartPos.iY; + TInt xPos = aStartPos.iX; + for (TInt yy = 0; yy < aSize.iHeight; ++yy) + { + ptr = reinterpret_cast(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(surfacePtr); + + // Fill the rectangle + TInt yPos = aStartPos.iY; + TInt xPos = aStartPos.iX; + for (TInt yy = 0; yy < aSize.iHeight; ++yy) + { + ptr = reinterpret_cast(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(KAllScreens, 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(surfacePtr); + + // Fill the rectangle + TInt yPos = aStartPos.iY; + TInt xPos = aStartPos.iX; + for (TInt yy = 0; yy < aSize.iHeight; ++yy) + { + ptr = reinterpret_cast(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(surfacePtr); + + // Fill the rectangle + TInt yPos = aStartPos.iY; + TInt xPos = aStartPos.iX; + for (TInt yy = 0; yy < aSize.iHeight; ++yy) + { + ptr = reinterpret_cast(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(surfacePtr); + + // Fill first line + for (TInt xx1 = 0; xx1 < info.iSize.iWidth; xx1++) + { + ptr[xx1] = (TUint16)lines; + } + + // Fill second line + ptr = reinterpret_cast(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(surfacePtr); + + // Fill first line + for (TInt xx3 = 0; xx3 < info.iSize.iWidth; xx3++) + { + ptr[xx3] = lines; + } + + // Fill second line + ptr = reinterpret_cast(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(KAllScreens, 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 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 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(innerXY,info.iStride/2,(TUint16*)surfacePtr,linesTL,linesBR,linesBL,linesTR); + } + else + { + if ( info.iSize.iWidth*4>info.iStride) + { + User::Leave(KErrOverflow); + } + FanFill(innerXY,info.iStride/4,(TUint*)surfacePtr,linesTL,linesBR,linesBL,linesTR); + } + + chunk.Close(); + + iSurfaceUpdateSession.SubmitUpdate(KAllScreens, 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((info.iSize.iWidth*aPosition)/100,0,(info.iSize.iWidth*aPosition)/100, + info.iSize.iHeight-1,info.iStride/2,(TUint16*)surfacePtr,lineColor); + } + else + { + DdaLine((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(KAllScreens, 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;yDataStride(); + } + 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(KAllScreens, 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(KAllScreens, 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(KAllScreens, 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; + } +