graphicscomposition/openwfcompositionengine/test/tscreeninterface/streamutility.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 16:31:06 +0300
branchRCL_3
changeset 163 bbf46f59e123
permissions -rw-r--r--
Revision: 201029 Kit: 201035

// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
//
// Description:
//

/**
 @file
*/

#include <e32std.h>
#include <imageconversion.h>
#include <graphics/symbianstream.h>
#include "streamutility.h"

#define WFC_INVALID_HANDLE NULL

CStreamUtility::CStreamUtility()
	{
	}
	
CStreamUtility* CStreamUtility::NewL()
	{
	CStreamUtility* utility = new (ELeave)CStreamUtility();
	CleanupStack::PushL(utility);
	utility->ConstructL();
	CleanupStack::Pop(utility);
	return utility;
	}
	
void CStreamUtility::ConstructL()
	{
	TInt r = iManager.Open();
	if (r != KErrNone)
		{
		LOG(("Surface manager failed to open: %d", r));
		User::Leave(r);
		}
	}
	
CStreamUtility::~CStreamUtility()
	{
	DestroyAll();

	iStreams.Close();

	iManager.Close();
	}

TBool CStreamUtility::DestroyAll()
	{
	TInt err = 	KErrNone;
	TInt jj = iStreams.Count() - 1;
	if (jj<0)
		return EFalse;
	for (; jj >= 0; jj--)
		{
        //The following lines are just to get the surface ID for verification
		SymbianStreamBuffer bufferHandle;
		User::LeaveIfError(SymbianStreamAcquireReadBuffer(iStreams[jj], &bufferHandle));
		long bufferIndex;
		const TSurfaceId* pSurfaceId = NULL;
		
		User::LeaveIfError(SymbianStreamGetBufferId(iStreams[jj],bufferHandle,&bufferIndex,&pSurfaceId));
        User::LeaveIfError(SymbianStreamReleaseReadBuffer(iStreams[jj], bufferHandle));
        
        const TSurfaceId surfaceId = *pSurfaceId;   //Need to copy my reference to the ID.
        //Actually release the stream
        SymbianStreamRemoveReference(iStreams[jj]);
        
        //Verify the stream is now not accessible
        TInt offset;
		err = iManager.GetBufferOffset(surfaceId,0,offset);
		if (err==KErrNone)
			{
			LOG(("Closing stream via DestoryAll did not destroy surface!"));
			}
		}
	iStreams.Reset();
	return ETrue;
	}

/***************************************
 * The aim of the RHeapStreamArray is to locally switch in the specified heap for any array operation
 ***************************************/

CStreamUtility::RHeapStreamArray::RHeapStreamArray(RHeapStreamArray* aUseExternalArray)
	:	iUseArray(aUseExternalArray?aUseExternalArray->iUseArray:&this->iLocalArray),
	iExternalHeapRef(aUseExternalArray?aUseExternalArray->iExternalHeapRef:User::Heap())
	{
	
	}
/************************************
 * The following methods have been used by the streamutility... some require the heap wrapping, and some don't
 * I actually need three different strategies (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	CStreamUtility::RHeapStreamArray::PopHeap(void* aHeapPtr)
	{
	RHeap* heapPtr=(RHeap*)aHeapPtr;
	User::SwitchHeap(heapPtr);
	}

SymbianStreamType& CStreamUtility::RHeapStreamArray::operator[](TUint aIndex)
	{
	return iUseArray->operator[](aIndex);
	}

/// Close only closes the local array, while Reset resets the active array (may be external)
void CStreamUtility::RHeapStreamArray::Close()
	{
	iLocalArray.Close();
	}

TInt CStreamUtility::RHeapStreamArray::Count() const
	{
	return iUseArray->Count();
	}

/// Close only closes the local array, while Reset resets the active array (may be external)
inline void CStreamUtility::RHeapStreamArray::Reset()
	{
	iUseArray->Reset();
	}

void CStreamUtility::RHeapStreamArray::AppendL(const SymbianStreamType &anEntry)
	{
	iUseArray->AppendL(anEntry);
	}

TInt CStreamUtility::RHeapStreamArray::Find(const SymbianStreamType &anEntry) const
	{
	return iUseArray->Find(anEntry);
	}

void CStreamUtility::RHeapStreamArray::Remove(TInt anIndex)
	{
	iUseArray->Remove(anIndex);
	}

/**
Cleanup stack helper object, holding references to both utility and stream, so
that the standard Close() semantics can be used.
*/
class TStreamCleanup
	{
public:
	TStreamCleanup(CStreamUtility& aUtility, SymbianStreamType& aStream)
		: iUtility(aUtility), iStream(aStream)
		{}
	void Close()
		{
		// Removes the stream from the list of streams to clean up, and closes
		// the stream reference.
		iUtility.DestroyStream(iStream);
		}
private:
	CStreamUtility& iUtility;
	SymbianStreamType& iStream;
	};

/**
Get the size of a stream.

@param  aStream The stream to get the size for.
@return The size in pixels, or empty on failure.
*/
TSize CStreamUtility::StreamSize(const SymbianStreamType aStream)
	{
	khronos_int32_t width;
	khronos_int32_t height;
	khronos_int32_t stride;
	khronos_int32_t format;
	khronos_int32_t pixelSize;
		
	SymbianStreamGetHeader(aStream, &width, &height, &stride, &format, &pixelSize);
	
	TSize size = TSize(static_cast<TInt>(width), static_cast<TInt>(height));
	
	return size;
	}

/**
Create a stream using the surface manager.

Stores the ID for tear down, as well as returning it.

@param aSize            Dimensions of the stream.
@param aPixelFormat	    UID of the pixel format.
@param aStride	        Stride value for the stream (usually bytes per pixel * width)
@param aReturnSurface   Returns TSurfaceId wrapped by the stream
@param aContiguous      Contiguous flag for creating surfaces
@param aBuffers         Number of buffers
@leave May leave due to lack of memory.
@return New stream's ID.
*/
SymbianStreamType CStreamUtility::CreateStreamL(const TSize& aSize, TUidPixelFormat aPixelFormat, 
                                            TInt aStride, TSurfaceId& aReturnSurface, 
                                            TBool aContiguous, TInt aBuffers)
	{
	RSurfaceManager::TSurfaceCreationAttributesBuf bf;
	RSurfaceManager::TSurfaceCreationAttributes& b = bf();
	if (aStride<aSize.iWidth*BytesPerPixelL(aPixelFormat))
	    {
	    User::Leave(KErrOverflow);
	    }
	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 = !!aContiguous;
	b.iMappable = ETrue;

	aReturnSurface = TSurfaceId::CreateNullId();

	User::LeaveIfError(iManager.CreateSurface(bf, aReturnSurface));
	
	SymbianStreamType ns;
	TInt err = SymbianStreamAcquire(&aReturnSurface, &ns);
    iManager.CloseSurface(aReturnSurface);		//The stream should now own the only reference
	if (err != KErrNone)
		{
		User::Leave(err);	
		}
	iStreams.AppendL(ns);
	return ns;
	}

/**
Fill the given stream with a color.

@param aStream	The stream to be filled.
@param aColor	The color to fill it with.
*/
void CStreamUtility::FillStreamL(SymbianStreamType aStream, const TRgb& aColor)
	{
	
	khronos_int32_t width;
	khronos_int32_t height;
	khronos_int32_t stride;
	khronos_int32_t format;
	khronos_int32_t pixelSize;
		
	SymbianStreamGetHeader(aStream, &width, &height, &stride, &format, &pixelSize);

	TUint32 color = 0;
	TBool use16 = EFalse;

	if (height<0 || width<0 || stride<0)
		{
		User::Leave(KErrCorrupt);
		}
	if (height==0 || width==0 || stride==0)
		{
		User::Leave(KErrNotReady);
		}

	switch (format)
		{
		case EUidPixelFormatXRGB_8888:
			{
			color = aColor.Color16MU();
			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;
			}
		}

    SymbianStreamBuffer bufferHandle;
    User::LeaveIfError(SymbianStreamAcquireWriteBuffer(aStream, &bufferHandle));
    long bufferIndex;
    const TSurfaceId* surfaceId = NULL;
    User::LeaveIfError(SymbianStreamGetBufferId(aStream,bufferHandle,&bufferIndex,&surfaceId));

	RChunk chunk;
	User::LeaveIfError(iManager.MapSurface(*surfaceId, chunk));
	CleanupClosePushL(chunk);

	TInt offsetToFirstBuffer;
	User::LeaveIfError(iManager.GetBufferOffset(*surfaceId, 0, offsetToFirstBuffer));
	TUint8* streamPtr = chunk.Base() + offsetToFirstBuffer;
	TUint8* linePtr = streamPtr;

	if (use16)
		{
		if ( width*2>stride)
			{
			User::Leave(KErrOverflow);
			}
		TUint16* ptr = reinterpret_cast<TUint16*>(streamPtr);

		// Fill first line
		for (TInt xx = 0; xx < width; xx++)
			{
			ptr[xx] = (TUint16)color;
			}
		}
	else
		{
		if ( width*4>stride)
			{
			User::Leave(KErrOverflow);
			}
		TUint32* ptr = reinterpret_cast<TUint32*>(streamPtr);

		// Fill first line
		for (TInt xx = 0; xx < width; xx++)
			{
			ptr[xx] = color;
			}
		}

	// Now copy that to the other lines
	for (TInt yy = 1; yy < height; yy++)
		{
		linePtr += stride;
		Mem::Copy(linePtr, streamPtr, width * BytesPerPixelL(aStream));
		}
	User::LeaveIfError(SymbianStreamReleaseWriteBuffer(aStream, bufferHandle));
	CleanupStack::PopAndDestroy(/* chunk */);
	}

/**
Destroy a stream.

As well as destroying the stream, it is removed from the set held for
destruction during tear down.

@param aStream	The stream to be destroyed.
*/
void CStreamUtility::DestroyStream(SymbianStreamType aStream)
	{
	TInt index = iStreams.Find(aStream);
	
	if (index != KErrNotFound)
		{
		iStreams.Remove(index);
		}

	SymbianStreamRemoveReference(aStream);
	}

/**
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 CStreamUtility::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;
    }

/**
A helper function that returns the bytes per pixel for a given stream

@param      aStream The stream which is checked
@return     The bytes per pixel
*/
TInt CStreamUtility::BytesPerPixelL(const SymbianStreamType aStream)
    {
    khronos_int32_t width;
    khronos_int32_t height;
    khronos_int32_t stride;
    khronos_int32_t format;
    khronos_int32_t pixelSize;
        
    SymbianStreamGetHeader(aStream, &width, &height, &stride, &format, &pixelSize);

    return static_cast<TInt>(pixelSize);
    }