diff -r 000000000000 -r 5d03bc08d59c graphicscomposition/openwfsupport/src/surfacestream.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graphicscomposition/openwfsupport/src/surfacestream.cpp Tue Feb 02 01:47:50 2010 +0200 @@ -0,0 +1,2134 @@ +// Copyright (c) 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: +// SurfaceStream.cpp +// CSurfaceStream implementation + +#include +#include +#include +#include +#include "surfacestream.h" +#include "openwfcpanic.h" +#include "streammap.h" +#include "symbianstream.h" +#define WFC_INVALID_HANDLE NULL + +const TInt KInvalidIndex = KNoAssociatedScreenNumber; + +struct CSurfaceStream::TCallBackEntry + { + typedef SymbianStreamCallback TSimpleCallback; + TCallBackEntry(); + void Reset(); + TSimpleCallback iCallBackFunction; + TAny* iCallBackClientParam; + TInt32 iEventMask; + TInt32 iScreenNumber; + }; + +CSurfaceStream::TCallBackEntry::TCallBackEntry(): +iCallBackFunction(NULL), +iCallBackClientParam(NULL), +iEventMask(ESOWF_NoEvent), +iScreenNumber(KNoAssociatedScreenNumber) + { + } + +void CSurfaceStream::TCallBackEntry::Reset() + { + iCallBackFunction = NULL; + iCallBackClientParam = NULL; + iEventMask = ESOWF_NoEvent; + iScreenNumber = KNoAssociatedScreenNumber; + } + +struct CSurfaceStream::TGlobalNotification + { + TGlobalNotification(); + void Reset(); + TRequestStatus* iStatus; + TThreadId iThreadId; + TInt iPendingNotifications; + TInt iCompletedOkNotifications; + TInt iCanceledNotifications; + TInt iOverflowedNotifications; + TInt iNotVisibleNotifications; + TInt iOtherNotifications; + }; + + +CSurfaceStream::TGlobalNotification::TGlobalNotification(): +iStatus(NULL), +iThreadId(0), +iPendingNotifications(0), +iCompletedOkNotifications(0), +iCanceledNotifications(0), +iOverflowedNotifications(0), +iNotVisibleNotifications(0), +iOtherNotifications(0) + { + + } + +void CSurfaceStream::TGlobalNotification::Reset() + { + iStatus = NULL; + iThreadId = 0; + iPendingNotifications = 0; + iCompletedOkNotifications = 0; + iCanceledNotifications = 0; + iOverflowedNotifications = 0; + iNotVisibleNotifications = 0; + iOtherNotifications = 0; + } + +struct CSurfaceStream::TNewGlobalNotifications + { + TNewGlobalNotifications(); + TInt iNewAvailableIdx; + TInt iNewDisplayedIdx; + TInt iNewDisplayedXIdx; + }; + +CSurfaceStream::TNewGlobalNotifications::TNewGlobalNotifications(): +iNewAvailableIdx(KInvalidIndex), +iNewDisplayedIdx(KInvalidIndex), +iNewDisplayedXIdx(KInvalidIndex) + { + } + +CSurfaceStream::Guard::Guard(RFastLock& aLock): +iLock(aLock) + { + iLock.Wait(); + } + +CSurfaceStream::Guard::~Guard() + { + iLock.Signal(); + } + +CSurfaceStream::CSurfaceStream(): + iSurfaceId(TSurfaceId::CreateNullId()), + iBufferInfo(NULL), + iProtected(EFalse), + iNumberOfScreenAttachedAvailableNotif(0), + iNumberOfScreenAttachedDisplayedNotif(0), + iNumberOfScreenAttachedDisplayedXNotif(), + iFlipState(EFlippedTargetNormal), + iNewFlip(EFlipNotSet) + { + iStreamProxySurfaceId.iInternal[TSurfaceId::TSurfaceUsage::EObjectRefField]= + reinterpret_cast(this); + iStreamProxySurfaceId.iInternal[TSurfaceId::TSurfaceUsage::ETypeClassField]= + TSurfaceId::EStreamHandle<ConstructL(aId); + return self; + } + +void CSurfaceStream::ConstructL(const TSurfaceId& aId) + { + User::LeaveIfError(iRefCountMutex.CreateLocal()); + User::LeaveIfError(iCallBacksMutex.CreateLocal()); + + RSurfaceManager::TInfoBuf infoBuf; + SurfaceInfoL(aId, infoBuf); + iInfo = infoBuf(); + + COpenWfcStreamMap& stream = GetSingletonL(); + //Create array for TBufferInfo + iBufferInfo = new(ELeave) TBufferInfo[iInfo.iBuffers]; + for(TInt i = 0; i < iInfo.iBuffers; i++) + { + TInt offset = 0; + switch(aId.Type()) + { + case TSurfaceTypes::ESurfaceManagerSurface: + { + User::LeaveIfError(stream.SurfaceManager().GetBufferOffset(iSurfaceId, + i, offset)); + break; + } + case TSurfaceId::EScreenSurface: + { + TInt screenId = SurfaceId().iInternal[TSurfaceId::TScreenSurfaceUsage::EScreenField]; + User::LeaveIfError(HAL::Get(screenId, HALData::EDisplayOffsetToFirstPixel, offset)); + break; + } + default: + User::Leave(KErrNotSupported); + } + + iBufferInfo[i].iRefCount = 0; + iBufferInfo[i].iOffset = offset; + } + } + +void CSurfaceStream::SurfaceInfoL(const TSurfaceId& aId, RSurfaceManager::TInfoBuf& aInfoBuf) + { + COpenWfcStreamMap& stream = GetSingletonL(); + switch(aId.Type()) + { + case TSurfaceTypes::ESurfaceManagerSurface: + { + iStreamProxySurfaceId.iInternal[TSurfaceId::TSurfaceUsage::EObjectRefField]= + reinterpret_cast(this); + iStreamProxySurfaceId.iInternal[TSurfaceId::TSurfaceUsage::ETypeClassField]= + TSurfaceId::EStreamHandle< (aId.iInternal[TSurfaceId::TScreenSurfaceUsage::ETypeGuidField]); + if (!pixelFormat) + { + //if (bpp==12 || bpp==4)) //This allows low-color indices to be semi-functionally tested + if (bpp==12) + { + pixelFormat = EUidPixelFormatXRGB_4444; + } + else if (bpp == 16) + { + pixelFormat = EUidPixelFormatRGB_565; + } + else if (bpp== 24 || bpp==32) + { + pixelFormat = EUidPixelFormatARGB_8888; + } + else + { + User::Leave(KErrNotSupported); + } + + } + aInfoBuf().iPixelFormat = pixelFormat; + +#ifdef SYMBIAN_ROTATION_MODE_CHANGES + TInt displayMode = aId.iInternal[TSurfaceId::TScreenSurfaceUsage::EHalField]; +#else + TInt displayMode = 0; + User::LeaveIfError(HAL::Get(screenId, HALData::EDisplayMode, displayMode)); +#endif + +#if defined(SYMBIAN_ROTATION_MODE_CHANGES) + if (displayMode & TSurfaceId::TScreenSurfaceUsage::EHalFlippedFlag) // 90 | 270 degree rotation + { + // Swap dimensions and recalculate stride. Assume no padding for now. + aInfoBuf().iSize.iWidth = height; + aInfoBuf().iSize.iHeight = width; + //"vertical" stride has already been fetched + } +#elif defined(SYMBIAN_ROTATION_CHANGES) + if (aSurface.iInternal[1] & (2 | 8)) // 90 | 270 degree rotation + { + // Swap dimensions and recalculate stride. Assume no padding for now. + aInfoBuf().iSize.iWidth = height; + aInfoBuf().iSize.iHeight = width; + aInfoBuf().iStride = infoBuf().iSize.width * bpp; + } +#endif + + TInt stride = displayMode; + User::LeaveIfError(HAL::Get(screenId, HALData::EDisplayOffsetBetweenLines, stride)); + + aInfoBuf().iStride = stride; + + iSurfaceId = aId; + break; + } + default: + User::Leave(KErrNotSupported); + } + } + +COpenWfcStreamMap& CSurfaceStream::GetSingletonL() + { + return COpenWfcStreamMap::InstanceL(); + } + +/** + Helper to resolve handle to stream object +**/ +/*static*/ +CSurfaceStream* CSurfaceStream::FromHandle(SymbianStreamType aNativeStreamHandle) + { + if (aNativeStreamHandle) + { + if (aNativeStreamHandle->Type()==TSurfaceId::EStreamHandle) + { + return reinterpret_cast(aNativeStreamHandle->iInternal[TSurfaceId::TSurfaceUsage::EObjectRefField]); + } + } + return NULL; + } + +/** + Helper to resolve handle to stream object +**/ +SymbianStreamType CSurfaceStream::ToHandle() + { + if (this) + { + return &iStreamProxySurfaceId; + } + else + { + return NULL; + } + } + + +/** Returns internal surface ID. + * + * @return surface id asociated with this stream + **/ +const TSurfaceId& CSurfaceStream::SurfaceId()const + { + return iSurfaceId; + } + +/*! + * \brief Increase stream's reference count by one. + * + */ + void CSurfaceStream::AddReference() + { + iRefCountMutex.Wait(); + iRefCount++; + iRefCountMutex.Signal(); + + } + +/*! + * \internal + * + * \brief Returns flag if reference count is now zero. + * + */ +TBool CSurfaceStream::RemainingReference() + { + iRefCountMutex.Wait(); + TBool countZero=iRefCount==0; + iRefCountMutex.Signal(); + return countZero; + } + + +/*! + * \brief Decrease stream's reference count by one and destroy + * the stream, if the reference count goes to zero. + * + * All acquired read & write buffers must be released + * before calling WFC_Native_Destroy. + * + */ +void CSurfaceStream::ReleaseReference() + { + iRefCountMutex.Wait(); + --iRefCount; + if (iRefCount < 1) + { + // it is required to signal the mutex before calling LockDestroy() + iRefCountMutex.Signal(); + TRAP_IGNORE(GetSingletonL().LockDestroy(this)); + } + else + { + iRefCountMutex.Signal(); + } + } + +/*! + * \brief Get stream "frame header". Can be used to query + * all or some of the frame properties. + * + * \param width Pointer to location where width parameter should be saved + * \param height Pointer to location where height parameter should be saved + * \param stride Pointer to location where stride (row size in bytes) + * parameter should be saved + * \param pixelSize Pointer to location where pizelSize (pixel size in bytes) if the format has more than 8 bits. + * For the formats with fewer than 8 bits per pixel, or ones that do not use packed pixel + * the parameter is a negative number + * parameter should be saved + + * Passing a NULL pointer implies that particular + * value is of no interest to caller. E.g. + * owfNativeStreamGetHeader(stream, &w, &h, NULL, NULL, NULL); + * would only fetch width & height parameters. + */ +void CSurfaceStream::GetHeader( khronos_int32_t* aWidth, + khronos_int32_t* aHeight, + khronos_int32_t* aStride, + SymOwfPixelFormat* aFormat, + khronos_int32_t* aPixelSize) + { + Guard g1(iRefCountMutex); + if (aWidth) + { + if (iFlipState == EFlippedTargetFlipped) + { + *aWidth = static_cast(iInfo.iSize.iHeight); + } + else + { + *aWidth = static_cast(iInfo.iSize.iWidth); + } + } + + if (aHeight) + { + if (iFlipState == EFlippedTargetFlipped) + { + *aHeight = static_cast(iInfo.iSize.iWidth); + } + else + { + *aHeight = static_cast(iInfo.iSize.iHeight); + } + } + if (aStride) + { + if (iFlipState == EFlippedTargetFlipped) + { + *aStride = Stride(iInfo.iSize.iHeight, iInfo.iPixelFormat); + } + else + { + *aStride = static_cast(iInfo.iStride); + } + } + if (aFormat) + { + *aFormat=iInfo.iPixelFormat; + } + if (aPixelSize) + { + *aPixelSize = static_cast(BytesPerPixel(iInfo.iPixelFormat)); + } + } + +/*! + * \brief Acquires read buffer for stream. For > 1 buffer + * streams this function doesn't block, but simply returns + * WFC_INVALID_HANDLE if no buffer is available for reading. + * For 1 buffer stream the caller is blocked until the buffer + * is ready for reading (the reader has committed the buffer, + * that is.) + * + * + * \return WFC_INVALID_HANDLE if no buffer is available or + * handle to last committed buffer. + * + * An example sequence for 3 buffer stream where + * producer produces frames approx. after every ~5th time unit. + * Consumer consumes buffers at constant rate of 1buf/time unit. + * Pframe is the number/handle of buffer that is being written by + * the producer (let's assume that it takes 2 time units + * for producer to produce a frame/buffer.) Cframe is the number/ + * handle of the buffer the consumer receives from AcquireReadBuffer(). + * "i" stands for WFC_INVALID_HANDLE: + * + * \code + * Time: 0 5 10 15 20 25 + * Pframe: 0 1 2 0 1 ... + * Cframe: ii00000111112222200000111... + * \endcode + */ +SymbianStreamBuffer CSurfaceStream::AcquireReadBuffer() + { + SymbianStreamBuffer buffer = WFC_INVALID_HANDLE; + + iRefCountMutex.Wait(); + TInt index = GetReadBufferIndex(); + buffer = IndexToReadHandle(index); + ++(iBufferInfo[index].iRefCount); + iRefCountMutex.Signal(); + AddReference(); + return buffer; + } + +/*! + * \brief Releases read buffer. + * + * When read buffer is released, it is marked as clean to + * be written again, unless it is the only committed buffer + * in which case it is recycled so that the same buffer + * can be read again (as long as no new buffers are committed + * by the producer) + * + * \param buf Buffer handle. Must be valid read buffer handle for + * given stream. + */ +TInt CSurfaceStream::ReleaseReadBuffer(SymbianStreamBuffer aBuf) + { + TInt index = BufferHandleToIndex(aBuf); + if(index < 0 || index >= iInfo.iBuffers) + { + return KErrBadHandle; + } + + iRefCountMutex.Wait(); + + __ASSERT_DEBUG(iBufferInfo[index].iRefCount > 0, + (iRefCountMutex.Signal(),Panic(EOwfPanicSurfaceStreamBufferNotLocked))); + + --(iBufferInfo[index].iRefCount); + + iRefCountMutex.Signal(); + ReleaseReference(); + return KErrNone; + } + +/*! + * \brief Acquires write buffer for stream. + * + * Returns handle to a buffer that can be used to write + * data into stream. If no clean buffer is available, + * invalid handle is returned. + * + * + * \return Handle to a writable buffer + */ +SymbianStreamBuffer CSurfaceStream::AcquireWriteBuffer() + { + SymbianStreamBuffer buffer = WFC_INVALID_HANDLE; + + iRefCountMutex.Wait(); + TInt index = GetWriteBufferIndex(); + //Writers are currently not blocked in single buffered, + //but if proper signalling was implemented then they could be blocked + //Ideally, make signalling/blocking a parameter flag of AcquireWriteBuffer + if (iInfo.iBuffers>1 && iBufferInfo[index].iRefCount > 0) + { + buffer = WFC_INVALID_HANDLE; + } + else + { + buffer = IndexToWriteHandle(index); + ++(iBufferInfo[index].iRefCount); + iAcquiredWriteBuffer = buffer; + } + iRefCountMutex.Signal(); + if (buffer) + { + AddReference(); + } + return buffer; + } + +/*! + * \brief Releases write buffer to stream. + * Released buffer is made new front buffer, i.e., producer is expected + * to release buffer is the same order they were acquired. + * + * \param buf Buffer handle. Must be valid write buffer handle + * for given stream. + */ +void CSurfaceStream::ReleaseWriteBuffer(SymbianStreamBuffer aBuf) + { + TInt index = BufferHandleToIndex(aBuf); + if(index < 0 || index >= iInfo.iBuffers) + { + return; + } + + iRefCountMutex.Wait(); + + __ASSERT_DEBUG(iBufferInfo[index].iRefCount > 0, + (iRefCountMutex.Signal(),Panic(EOwfPanicSurfaceStreamBufferNotLocked))); + + __ASSERT_DEBUG((iAcquiredWriteBuffer == aBuf) || (iAcquiredWriteBuffer == BUFFER_WRITE_UPDATE_OVERWRITE), + (iRefCountMutex.Signal(),Panic(EOwfPanicSurfaceStreamBufferNotLocked))); + + if (iAcquiredWriteBuffer != BUFFER_WRITE_UPDATE_OVERWRITE) + { + // Update read buffer to point to buffer just finished writing + SetReadBufferIndex(index); + } + iAcquiredWriteBuffer = WFC_INVALID_HANDLE; + + --(iBufferInfo[index].iRefCount); + + if (iNewFlip != EFlipNotSet) + { + iFlipState = iNewFlip; + iNewFlip = EFlipNotSet; + } + + iRefCountMutex.Signal(); + + NotifyObservers(ESOWF_EventComposed); + ReleaseReference(); //Note this means this NotifyObservers can never get the rug pulled out + } + + +void CSurfaceStream::SetReadBufferIndex(TInt aIndex) + { + __ASSERT_DEBUG(aIndex >= 0 && aIndex < iInfo.iBuffers, + (iRefCountMutex.Signal(),Panic(EOwfPanicSurfaceStreamBufferIndexOutOfBounds))); + iReadBuffer = aIndex; + } + +TInt CSurfaceStream::GetReadBufferIndex() + { + return iReadBuffer; + } +TInt CSurfaceStream::GetWriteBufferIndex() + { + return (iReadBuffer+1)%iInfo.iBuffers; + } + +/*! \brief Returns pointer to pixel buffer. + * + * \param buffer Handle of buffer + */ +void* CSurfaceStream::GetBufferPtrL(SymbianStreamBuffer aBuffer) + { + TInt bufferIndex = BufferHandleToIndex(aBuffer); + Guard g1(iRefCountMutex); + __ASSERT_DEBUG(iBufferInfo[bufferIndex].iRefCount > 0, + (iRefCountMutex.Signal(),Panic(EOwfPanicSurfaceStreamBufferNotLocked))); + + switch (SurfaceId().Type()) + { + case TSurfaceTypes::ESurfaceManagerSurface: + { + if (iBufferChunk.Handle() == 0) + { + RChunk threadChunk; + User::LeaveIfError(GetSingletonL().SurfaceManager().MapSurface(iSurfaceId, threadChunk)); + CleanupClosePushL(threadChunk); + + RChunk duplicateChunk; + duplicateChunk.SetHandle(threadChunk.Handle()); + User::LeaveIfError(duplicateChunk.Duplicate(RThread(), EOwnerProcess)); + + iBufferChunk.SetHandle(duplicateChunk.Handle()); + CleanupStack::PopAndDestroy(&threadChunk); + } + break; + } + case TSurfaceId::EScreenSurface: + { + if (iBufferChunk.Handle() == 0) + { + TInt val = 0; + TInt screenId = SurfaceId().iInternal[TSurfaceId::TScreenSurfaceUsage::EScreenField]; + User::LeaveIfError(HAL::Get(screenId, HALData::EDisplayMemoryHandle, val)); + + RChunk threadChunk; + CleanupClosePushL(threadChunk); + User::LeaveIfError(threadChunk.SetReturnedHandle(val)); + + RChunk duplicateChunk; + duplicateChunk.SetHandle(threadChunk.Handle()); + User::LeaveIfError(duplicateChunk.Duplicate(RThread(), EOwnerProcess)); + + iBufferChunk.SetHandle(duplicateChunk.Handle()); + CleanupStack::PopAndDestroy(&threadChunk); + } + break; + } + default: + User::Leave(KErrNotSupported); + } + + TUint8 *pBufferStart = iBufferChunk.Base() + iBufferInfo[bufferIndex].iOffset; + return static_cast(pBufferStart); + } + +void CSurfaceStream::SetProtectionFlag(TBool aFlag) + { + iRefCountMutex.Wait(); + if (aFlag!=iProtected) + { + iProtected=aFlag; + iRefCountMutex.Signal(); + if (aFlag) + { + AddReference(); + } + else + { + ReleaseReference(); + } + } + else + { + iRefCountMutex.Signal(); + } + } + +TInt CSurfaceStream::BytesPerPixel(TUidPixelFormat aPixelFormat) + { + switch (aPixelFormat) + { + case EUidPixelFormatXRGB_8888: + case EUidPixelFormatARGB_8888: + case EUidPixelFormatBGRX_8888: + case EUidPixelFormatXBGR_8888: + case EUidPixelFormatBGRA_8888: + case EUidPixelFormatABGR_8888: + case EUidPixelFormatABGR_8888_PRE: + case EUidPixelFormatARGB_8888_PRE: + case EUidPixelFormatBGRA_8888_PRE: + case EUidPixelFormatARGB_2101010: + case EUidPixelFormatABGR_2101010: + return 4; + case EUidPixelFormatBGR_888: + case EUidPixelFormatRGB_888: + return 3; + case EUidPixelFormatXRGB_4444: + case EUidPixelFormatARGB_4444: + case EUidPixelFormatXBGR_4444: + case EUidPixelFormatRGB_565: + case EUidPixelFormatBGR_565: + case EUidPixelFormatARGB_1555: + case EUidPixelFormatXRGB_1555: + case EUidPixelFormatARGB_8332: + case EUidPixelFormatBGRX_5551: + case EUidPixelFormatBGRA_5551: + case EUidPixelFormatBGRA_4444: + case EUidPixelFormatBGRX_4444: + case EUidPixelFormatAP_88: + return 2; + case EUidPixelFormatRGB_332: + case EUidPixelFormatBGR_332: + case EUidPixelFormatA_8: + case EUidPixelFormatL_8: + return 1; + case EUidPixelFormatP_8: + return -1; + case EUidPixelFormatP_4: + case EUidPixelFormatL_4: + return -2; + case EUidPixelFormatL_2: + case EUidPixelFormatP_2: + return -4; + case EUidPixelFormatL_1 : + return -8; + default: + { + return 0; + } + } + } + +SymbianStreamBuffer CSurfaceStream::IndexToReadHandle(TInt aIndex) + { + return static_cast(aIndex + BUFFER_READ_HANDLE_BASE); + } + +SymbianStreamBuffer CSurfaceStream::IndexToWriteHandle(TInt aIndex) + { + return static_cast(aIndex + BUFFER_WRITE_HANDLE_BASE); + } + +TInt CSurfaceStream::BufferHandleToIndex(SymbianStreamBuffer aBuff) + { + TInt retVal= (aBuff > 0) ? (aBuff&0xFF) : (aBuff - BUFFER_READ_HANDLE_BASE); + __ASSERT_DEBUG(retVal>=0,User::Invariant()); + __ASSERT_DEBUG(retVal 0) + { + status = KErrNone; + } + else if (globalNotification.iOverflowedNotifications > 0) + { + status = KErrOverflow; + } + else if (globalNotification.iNotVisibleNotifications > 0) + { + status = KErrNotVisible; + } + else if (globalNotification.iCanceledNotifications > 0) + { + status = KErrCancel; + } + else + { + status = KErrGeneral; + } + + RThread thread; + if (thread.Open(globalNotification.iThreadId) == KErrNone) + { + NFLOG(("### CSurfaceStream::RequestComplete globalIndex[%d] aRequestComplete(0x%x) status(%d)", + aGlobalIndexArray, iGlobalNotifications[aGlobalIndexArray].iStatus, status)); + thread.RequestComplete(globalNotification.iStatus, status); + thread.Close(); + iGlobalNotifications[aGlobalIndexArray].Reset(); + } + } + } + else + { + RThread thread; + if (thread.Open(aThreadId) == KErrNone) + { + NFLOG(("### CSurfaceStream::RequestComplete aRequestStatus(0x%x) aThreadId(0x%x) aStatus(%d)", + aRequestStatus, aThreadId, aStatus)); + thread.RequestComplete(aRequestStatus, aStatus); + thread.Close(); + } + } + aRequestStatus = NULL; + aThreadId = 0; + } + aGlobalIndexArray = KInvalidIndex; + } + +int CSurfaceStream::AddObserver(SymbianStreamCallback aObserver, + TInt32 aEvent, + TInt32 aScreenNumber, + void* aData) + { + if (!(aEvent & ESOWF_AllEventsMask) || !aData) + { + // early exit if the parameters are invalid + return KErrArgument; + } + + TInt errRet = KErrNone; + TCallBackEntry newEntry; + + Guard g2(iCallBacksMutex); + Guard g1(iRefCountMutex); + + // Let's do the check that we dont have an other similar observer already inserted + // traverse the whole aobservers list to see if there is already an observer in place + TInt idx = iCallBacks.Count(); + while(idx--) + { + if (iCallBacks[idx].iEventMask == aEvent) + { + switch (aEvent) + { + case ESOWF_EventAvailable: + case ESOWF_EventDisplayed: + case ESOWF_EventDisplayedX: + // these are events related to a context and identified by a screen number + if (iCallBacks[idx].iScreenNumber == aScreenNumber) + { + // nothing else to do, the entry is already created + return KErrOverflow; + } + break; + + case ESOWF_EventComposed: + case ESOWF_EventUpdated: + if (iCallBacks[idx].iCallBackClientParam == aData) + { + // nothing else to do, the entry is already created + return KErrOverflow; + } + break; + + default: + // something really unexpected, let's invalidate the entry + // possible memomry leaks but we are, still, alive and running. + iCallBacks[idx].Reset(); + break; + } + } + } + + // we need to add a new observer to the list + newEntry.iCallBackFunction = aObserver; + newEntry.iEventMask = aEvent; + newEntry.iScreenNumber = aScreenNumber; + TInt trapErr; + switch (aEvent) + { + case ESOWF_EventUpdated: + case ESOWF_EventComposed: + newEntry.iCallBackClientParam = aData; + break; + + case ESOWF_EventAvailable: + { + TNotificationAvailable* available = NULL; + TRAP(trapErr,available = new(ELeave) TNotificationAvailable()); + if (trapErr != KErrNone) + { + return trapErr; + } + ResetCallBackData(available, aEvent); + available->iSerialNumber = KInitialContextSerialNumber; + newEntry.iCallBackClientParam = available; + } + break; + + case ESOWF_EventDisplayed: + { + TNotificationDisplayed* displayed = NULL; + TRAP(trapErr,displayed = new(ELeave) TNotificationDisplayed()); + if (trapErr != KErrNone) + { + return trapErr; + } + ResetCallBackData(displayed, aEvent); + displayed->iSerialNumber = KInitialContextSerialNumber; + newEntry.iCallBackClientParam = displayed; + } + break; + + case ESOWF_EventDisplayedX: + { + TNotificationDisplayedX* displayedX = NULL; + TRAP(trapErr,displayedX = new(ELeave) TNotificationDisplayedX()); + if (trapErr != KErrNone) + { + return trapErr; + } + ResetCallBackData(displayedX, aEvent); + displayedX->iSerialNumber = KInitialContextSerialNumber; + newEntry.iCallBackClientParam = displayedX; + } + break; + + default: + return KErrArgument; + } + + // look for an entry that already exists + idx = iCallBacks.Count(); + + while(idx--) + { + // the free entry positions are identified using event mask + if (iCallBacks[idx].iEventMask == ESOWF_NoEvent) break; + } + + if (idx > -1) + { + // ok, we got an existing, free entry + iCallBacks[idx] = newEntry; + } + else + { + errRet = iCallBacks.Append(newEntry); + if (errRet != KErrNone) + { + return errRet; + } + } + + switch (aEvent) + { + case ESOWF_EventAvailable: + iNumberOfScreenAttachedAvailableNotif++; + break; + + case ESOWF_EventDisplayed: + iNumberOfScreenAttachedDisplayedNotif++; + break; + + case ESOWF_EventDisplayedX: + iNumberOfScreenAttachedDisplayedXNotif++; + break; + + default: + break; + + } + + return errRet; + } + + +int CSurfaceStream::RemoveObserver(TInt32 aEvents, void* aData) + { + NFLOG(("ENTER ###CSurfaceStream::RemoveObserver() events(%d) data(0x%x)", aEvents, aData)); + if (!(aEvents & ESOWF_AllEventsMask)) + { + NFLOG(("EXIT ###CSurfaceStream::RemoveObserver() ERROR: KErrArgument")); + return KErrArgument; + } + + Guard g2(iCallBacksMutex); + Guard g1(iRefCountMutex); + + TInt32 notFoundEvent = aEvents; + TInt count = iCallBacks.Count(); + TInt32 susScreenNumber = KNoAssociatedScreenNumber; + + if (aData) + { + susScreenNumber = *(((TInt32*)aData)); + } + + while (count-- && notFoundEvent) + { + TInt32 currentEvent = iCallBacks[count].iEventMask; + if (currentEvent & aEvents) + { + void* callBackData = iCallBacks[count].iCallBackClientParam; + switch (currentEvent) + { + case ESOWF_EventDisplayed: + if (callBackData && (!aData || (iCallBacks[count].iScreenNumber == susScreenNumber))) + { + Displayed(ESOWF_ObserverCancel, iCallBacks[count].iScreenNumber, NULL, callBackData, NULL); + delete callBackData; + iCallBacks[count].Reset(); + if (iNumberOfScreenAttachedDisplayedNotif > 0) + { + iNumberOfScreenAttachedDisplayedNotif--; + } + notFoundEvent &= ~currentEvent; + } + break; + + case ESOWF_EventAvailable: + if (callBackData && (!aData || (iCallBacks[count].iScreenNumber == susScreenNumber))) + { + Available(ESOWF_ObserverCancel, iCallBacks[count].iScreenNumber, NULL, callBackData, NULL); + delete callBackData; + iCallBacks[count].Reset(); + if (iNumberOfScreenAttachedAvailableNotif > 0) + { + iNumberOfScreenAttachedAvailableNotif--; + } + notFoundEvent &= ~currentEvent; + } + break; + + case ESOWF_EventDisplayedX: + if (callBackData && (!aData || (iCallBacks[count].iScreenNumber == susScreenNumber))) + { + DisplayedXTimes(ESOWF_ObserverCancel, iCallBacks[count].iScreenNumber, NULL, callBackData, NULL); + delete callBackData; + iCallBacks[count].Reset(); + if (iNumberOfScreenAttachedDisplayedXNotif) + { + iNumberOfScreenAttachedDisplayedXNotif--; + } + notFoundEvent &= ~currentEvent; + } + break; + + case ESOWF_EventComposed: + if (!aData || (aData == iCallBacks[count].iCallBackClientParam)) + { + // just in case that we have to delete the call back, we try, first to execute it + // avoiding in this way some deadlocks in CT code + if (iCallBacks[count].iCallBackFunction && iCallBacks[count].iCallBackClientParam) + { + iCallBacks[count].iCallBackFunction(ToHandle(), + ESOWF_EventComposed, + iCallBacks[count].iCallBackClientParam, + NULL); + } + iCallBacks[count].Reset(); + notFoundEvent &= ~currentEvent; + } + break; + + case ESOWF_EventUpdated: + if (!aData || (aData == iCallBacks[count].iCallBackClientParam)) + { + if (iCallBacks[count].iScreenNumber != KNoAssociatedScreenNumber) + { + susScreenNumber = iCallBacks[count].iScreenNumber; + iCallBacks[count].Reset(); + notFoundEvent &= ~currentEvent; + + // Reseting variables to loop back and remove SUS events. + notFoundEvent |= ESOWF_SUSEventsMask; + aEvents = ESOWF_SUSEventsMask; + count = iCallBacks.Count(); + } + else + { + iCallBacks[count].Reset(); + notFoundEvent &= ~currentEvent; + } + } + break; + + default: + break; + } + } + } + + NFLOG(("EXIT ###CSurfaceStream::CancelNotifications() err(%d)", notFoundEvent ? KErrNotFound : KErrNone)); + return (notFoundEvent ? KErrNotFound : KErrNone); + } + +TInt CSurfaceStream::NotifyObservers(TInt32 aEvent) + { + NFLOG(("### ENTER CSurfaceStream::NotifyObservers()")); + TInt err = KErrNotFound; + + Guard g2(iCallBacksMutex); + TCallBackEntry localCallBackEntry; + + for (TInt i = 0; i < iCallBacks.Count(); ++i) + { + localCallBackEntry = iCallBacks[i]; + if (iCallBacks[i].iEventMask & aEvent && + iCallBacks[i].iCallBackFunction) + { + err = KErrNone; + NFLOG(("### EXIT CSurfaceStream::NotifyObservers() callback(%d)", iCallBacks[i].iEventMask)); + localCallBackEntry.iCallBackFunction(ToHandle(), + iCallBacks[i].iEventMask, + localCallBackEntry.iCallBackClientParam, + NULL); + } + } + NFLOG(("### EXIT CSurfaceStream::NotifyObservers() err(%d)", err)); + return err; + } + +TBool CSurfaceStream::NotifyComposerContext(TInt32 aScreenNumber, TInt aOp, SYMOWF_CONTENT_UPDATED_PARAM* aParam) + { + NFLOG(("### ENTER CSurfaceStream::NotifyComposerContext()")); + TCallBackEntry entry; + TBool ret = EFalse; + for(TInt i = 0; i < iCallBacks.Count(); i++) + { + if (iCallBacks[i].iEventMask == ESOWF_EventUpdated && + iCallBacks[i].iCallBackFunction && + (((iCallBacks[i].iScreenNumber == KNoAssociatedScreenNumber) && (aOp != SYM_CONTENT_UPDATE_BEGIN)) || + ((aScreenNumber == KNoAssociatedScreenNumber) && (aOp != SYM_CONTENT_UPDATE_BEGIN)) || + iCallBacks[i].iScreenNumber == aScreenNumber)) + { + entry = iCallBacks[i]; + iRefCountMutex.Signal(); + NFLOG(("###CSurfaceStream::NotifyComposerContext() ESOWF_EventUpdated aParam(%d)", aParam? aParam->id: -1)); + entry.iCallBackFunction(ToHandle(), ESOWF_EventUpdated, entry.iCallBackClientParam, aParam); + ret = ETrue; + iRefCountMutex.Wait(); + } + } + NFLOG(("### EXIT CSurfaceStream::NotifyComposerContext() ret(%d)", ret)); + return ret; + } + +TBool CSurfaceStream::StartUpdateNotifications(TInt aScreenNumber, SYMOWF_CONTENT_UPDATED_PARAM& param) + { + NFLOG(("### CSurfaceStream::StartUpdateNotifications()")); + param.id = SYM_CONTENT_UPDATE_BEGIN; + param.length = sizeof (param); + param.par = 0; + param.serialNumber = KNoAssociatedScreenNumber; + param.immediateAvailable = 0; + return NotifyComposerContext(aScreenNumber, SYM_CONTENT_UPDATE_BEGIN, ¶m); + } + +TBool CSurfaceStream::EndUpdateNotifications(TInt aScreenNum, TInt aBufferNum, TInt32 aUpdatedFlags, const TRegion* aRegion) + { + (void)aScreenNum; + (void)aRegion; + NFLOG(("### CSurfaceStream::EndUpdateNotifications()")); + if (aBufferNum < 0 || aBufferNum >= iInfo.iBuffers) + { + return EFalse; + } + + if (iAcquiredWriteBuffer != WFC_INVALID_HANDLE) + { + iAcquiredWriteBuffer = BUFFER_WRITE_UPDATE_OVERWRITE; + } + + SetReadBufferIndex(aBufferNum); + + SYMOWF_CONTENT_UPDATED_PARAM param; + param.length = sizeof (param); + param.id = SYM_CONTENT_UPDATE_END; + param.par = aUpdatedFlags; + return NotifyComposerContext(aScreenNum, SYM_CONTENT_UPDATE_END, ¶m); + } + +TBool CSurfaceStream::UpdateNotifications(TInt aScreenNum, + TInt aBufferNum, + TInt32 aUpdatedFlags, + const TRegion* aRegion) + { + (void)aScreenNum; + (void)aRegion; + NFLOG(("### CSurfaceStream::UpdateNotifications()")); + if (aBufferNum < 0 || aBufferNum >= iInfo.iBuffers) + { + return EFalse; + } + + if (iAcquiredWriteBuffer != WFC_INVALID_HANDLE) + { + iAcquiredWriteBuffer = BUFFER_WRITE_UPDATE_OVERWRITE; + } + + SetReadBufferIndex(aBufferNum); + + SYMOWF_CONTENT_UPDATED_PARAM param; + param.length = sizeof (param); + param.id = SYM_CONTENT_UPDATE; + param.par = aUpdatedFlags; + return NotifyComposerContext(aScreenNum, SYM_CONTENT_UPDATE, ¶m); + } + +void CSurfaceStream::SetNewNotifications(TInt aBuffer, + TRequestStatus* aStatusDisplayed, TUint32* aTimeStamp, + TRequestStatus* aStatusDispXTimes, TInt* aDisplayedXTimes, + TRequestStatus* aStatusConsumed, const TRegion* aRegion, + TInt32 aScreenNumber) + { + NFLOG(("### ENTER * CSurfaceStream::SetNewNotifications()")); + Guard g2(iCallBacksMutex); + Guard g1(iRefCountMutex); + if (aScreenNumber == KAllScreens) + { + SetAllNotifications(aBuffer, + aStatusDisplayed, aTimeStamp, + aStatusDispXTimes, aDisplayedXTimes, + aStatusConsumed, aRegion); + } + else + { + TNewGlobalNotifications noGlobalNotifications; + SetNotifications(aBuffer, + aStatusDisplayed, aTimeStamp, + aStatusDispXTimes, aDisplayedXTimes, + aStatusConsumed, aRegion, + aScreenNumber, noGlobalNotifications); + } + NFLOG(("### EXIT * CSurfaceStream::SetNewNotifications()")); + } + + +void CSurfaceStream::SetNotifications(TInt aBuffer, + TRequestStatus* aStatusDisplayed, TUint32* aTimeStamp, + TRequestStatus* aStatusDispXTimes, TInt* aDisplayedXTimes, + TRequestStatus* aStatusConsumed, const TRegion* aRegion, + TInt32 aScreenNumber, const TNewGlobalNotifications& aGlobalNotifications) + { + NFLOG(("### ENTER * CSurfaceStream::SetNotifications()")); + TInt32 eventsFound = 0; + TInt32 eventsReceived = 0; + TInt32 eventsToProcess = 0; + TInt32 contextUpdate = 0; + // let's take in evidence the events we have to process + if (aStatusConsumed) + { + eventsReceived |= ESOWF_EventAvailable; + } + if (aStatusDisplayed) + { + eventsReceived |= ESOWF_EventDisplayed; + } + if (aStatusDispXTimes) + { + eventsReceived |= ESOWF_EventDisplayedX; + } + + TInt availableIndex = -1; + TInt displayedIndex = -1; + TInt displayedXIndex = -1; + + TInt32 serialNumber = KNoAssociatedScreenNumber; + TBool immediateAvailable = EFalse; + TInt32 immediateVisibility = SYM_CONTENT_VISIBLE_NOT_SET; + + // guard acquiring/release of the update lock of the composer + // acquire the update lock of the composer and retrive the composer state info + SYMOWF_CONTENT_UPDATED_PARAM param; + TBool startUpdateNotification = StartUpdateNotifications(aScreenNumber, param); + immediateAvailable = param.immediateAvailable && ETrue; + immediateVisibility = param.immediateVisibility; + serialNumber = param.serialNumber; + + + // we take, initially in consideration "availble" even if we might not have received a consumed request status + eventsToProcess = 0; + + // we try to figure out which are the vents we have to process and to get hold of their position + // in the observers array, in order to avoid traversing it again + TInt idx = iCallBacks.Count(); + //we will intend to mark the visited events, as an optimisation + TInt32 eventsToCheck = eventsReceived | ESOWF_EventAvailable; + TInt32 currentEvent = 0; + while(--idx > -1 && eventsToCheck) + { + currentEvent = iCallBacks[idx].iEventMask; + if ((currentEvent & eventsToCheck) && (iCallBacks[idx].iScreenNumber == aScreenNumber)) + { + switch (currentEvent) + { + case ESOWF_EventAvailable: + // mark observer visited + eventsToCheck &= ~currentEvent; + // mark the events found only if the corresponding status request has been recived + eventsFound |= (currentEvent & eventsReceived); + // reset the events to process mask + eventsToProcess &= ~currentEvent; + { + TNotificationAvailable* available = (TNotificationAvailable*) iCallBacks[idx].iCallBackClientParam; + if (available && (aStatusConsumed || available->iStatus || available->iNewStatus)) + { + // set the mask of the events to be processed because we have either to overflow some available request + // statuses, or to process them further + eventsToProcess |= ESOWF_EventAvailable; + availableIndex = idx; + } + } + break; + + case ESOWF_EventDisplayed: + // mark observer visited + eventsFound |= currentEvent; + eventsToProcess |= currentEvent; + eventsToCheck &= ~currentEvent; + displayedIndex = idx; + break; + + case ESOWF_EventDisplayedX: + // mark observer visited + eventsFound |= currentEvent; + eventsToProcess |= currentEvent; + eventsToCheck &= ~currentEvent; + displayedXIndex = idx; + break; + + default: + Panic(EOwfSymbianUnexpectedObserverId); + break; + } + } + } + + NFLOG(("### CSurfaceStream::SetNotifications eventsToProcess(0x%x)", eventsToProcess)); + if (eventsToProcess) + { + + // from this momment on, the composer cannot process any notifications related to this stream + + ContentUpdatedParams updateParameters(aBuffer, aStatusDisplayed, aTimeStamp, + aStatusDispXTimes, aDisplayedXTimes, + aStatusConsumed, aRegion, + immediateAvailable, immediateVisibility, + aGlobalNotifications); + + // process the observer corresponding to aStatusConsumed request status + if ((ESOWF_EventAvailable & eventsToProcess) && (availableIndex > -1)) + { + Available(ESOWF_ObserverProcessing, + serialNumber, + &updateParameters, + iCallBacks[availableIndex].iCallBackClientParam, + &contextUpdate); + } + + // process the observer corresponding to aStatusDisplayed request status + if ((ESOWF_EventDisplayed & eventsToProcess) && (displayedIndex > -1)) + { + Displayed(ESOWF_ObserverProcessing, + serialNumber, + &updateParameters, + iCallBacks[displayedIndex].iCallBackClientParam, + &contextUpdate); + } + + // process the observer corresponding to aStatusDispXTimes request status + if ((ESOWF_EventDisplayedX & eventsToProcess) && (displayedXIndex > -1)) + { + DisplayedXTimes(ESOWF_ObserverProcessing, + serialNumber, + &updateParameters, + iCallBacks[displayedXIndex].iCallBackClientParam, + &contextUpdate); + } + + } + + if (startUpdateNotification) + { + EndUpdateNotifications(aScreenNumber, aBuffer, contextUpdate, aRegion); + } + else + { + UpdateNotifications(aScreenNumber, aBuffer, contextUpdate, aRegion); + } + + if (eventsReceived != eventsFound) + { + if (aStatusConsumed && !(eventsFound & ESOWF_EventAvailable)) + { + User::RequestComplete(aStatusConsumed, KErrCancel); + } + + if (aStatusDisplayed && !(eventsFound & ESOWF_EventDisplayed)) + { + *aTimeStamp = 0; + User::RequestComplete(aStatusDisplayed, KErrCancel); + } + + if (aStatusDispXTimes && !(eventsFound & ESOWF_EventDisplayedX)) + { + User::RequestComplete(aStatusDispXTimes, KErrCancel); + } + } + NFLOG(("### EXIT * CSurfaceStream::SetNotifications()")); + } + +TInt CSurfaceStream::AddNewGlobalNotification(TRequestStatus* aStatusDisplayed, TInt aAssociatedScreens) + { + TInt maxIdx = iGlobalNotifications.Count(); + TInt retIdx = KInvalidIndex; + for (TInt i = 0; i < maxIdx; i++) + { + if (iGlobalNotifications[i].iStatus == NULL) + { + NFLOG(("### ENTER * CSurfaceStream::AddNewGlobalNotification found free idx(%d)", i)); + retIdx = i; + break; + } + } + + if (retIdx == KInvalidIndex) + { + TGlobalNotification newNotification; + if (iGlobalNotifications.Append(newNotification) == KErrNone) + { + retIdx = iGlobalNotifications.Count() - 1; + } + } + + if (retIdx != KInvalidIndex) + { + NFLOG(("### ENTER * CSurfaceStream::AddNewGlobalNotification populating idx(%d, status(%p) associated screens=0x%x)", retIdx, aStatusDisplayed, aAssociatedScreens)); + iGlobalNotifications[retIdx].Reset(); + iGlobalNotifications[retIdx].iStatus = aStatusDisplayed; + iGlobalNotifications[retIdx].iThreadId = RThread().Id(); + iGlobalNotifications[retIdx].iPendingNotifications = aAssociatedScreens; + } + + return retIdx; + } + +void CSurfaceStream::SetAllNotifications(TInt aBuffer, + TRequestStatus* aStatusDisplayed, TUint32* aTimeStamp, + TRequestStatus* aStatusDispXTimes, TInt* aDisplayedXTimes, + TRequestStatus* aStatusConsumed, const TRegion* aRegion) + { + NFLOG(("### ENTER * CSurfaceStream::SetAllNotifications()")); + TInt32 eventsToProcess = 0; + // let's take in evidence the events we have to process + + TNewGlobalNotifications newGlobalNotifications; + TInt idx = 0; + + if (aStatusConsumed && iNumberOfScreenAttachedAvailableNotif > 0) + { + if ((idx = AddNewGlobalNotification(aStatusConsumed, iNumberOfScreenAttachedAvailableNotif)) != KInvalidIndex) + { + newGlobalNotifications.iNewAvailableIdx = idx; + eventsToProcess |= ESOWF_EventAvailable; + } + } + + if (aStatusDisplayed && iNumberOfScreenAttachedDisplayedNotif > 0) + { + if ((idx = AddNewGlobalNotification(aStatusDisplayed, iNumberOfScreenAttachedDisplayedNotif)) != KInvalidIndex) + { + newGlobalNotifications.iNewDisplayedIdx = idx; + eventsToProcess |= ESOWF_EventDisplayed; + } + } + + if (aStatusDispXTimes && iNumberOfScreenAttachedDisplayedXNotif > 0) + { + if ((idx = AddNewGlobalNotification(aStatusDispXTimes, iNumberOfScreenAttachedDisplayedXNotif)) != KInvalidIndex) + { + newGlobalNotifications.iNewDisplayedXIdx = idx; + eventsToProcess |= ESOWF_EventDisplayedX; + } + } + + NFLOG(("### CSurfaceStream::SetAllNotifications eventsToProcess(0x%x)", eventsToProcess)); + + idx = iCallBacks.Count(); + TInt prevScreenNumber = KNoAssociatedScreenNumber; + TInt screenNumber = KNoAssociatedScreenNumber; + idx = iCallBacks.Count(); + while (idx--) + { + if (iCallBacks[idx].iCallBackClientParam && + (iCallBacks[idx].iEventMask == ESOWF_EventUpdated) && + ((screenNumber = iCallBacks[idx].iScreenNumber) != KNoAssociatedScreenNumber) + && prevScreenNumber != screenNumber) + { + NFLOG(("### CSurfaceStream::SetAllNotifications update composer %d", screenNumber)); + SetNotifications(aBuffer, + aStatusDisplayed, aTimeStamp, + aStatusDispXTimes, aDisplayedXTimes, + aStatusConsumed, aRegion, screenNumber, newGlobalNotifications); + + prevScreenNumber = screenNumber; + } + + } + + if (aStatusConsumed && !(eventsToProcess & ESOWF_EventAvailable)) + { + User::RequestComplete(aStatusConsumed, KErrCancel); + } + + if (aStatusDisplayed && !(eventsToProcess & ESOWF_EventDisplayed)) + { + *aTimeStamp = 0; + User::RequestComplete(aStatusDisplayed, KErrCancel); + } + + if (aStatusDispXTimes && !(eventsToProcess & ESOWF_EventDisplayedX)) + { + User::RequestComplete(aStatusDispXTimes, KErrCancel); + } + NFLOG(("### EXIT * CSurfaceStream::SetAllNotifications()")); + + } + +void CSurfaceStream::ProcessNotifications(TInt32 aEvent, + TInt32 aScreenNumber, + TInt32 aOperation, + TInt32 aSerialNumber, + TInt32* aReturnMask) + { + Guard g(iRefCountMutex); + NFLOG(("### ENTER CSurfaceStream::ProcessNotifications()")); + + TInt32 eventsToFind = aEvent & ESOWF_SUSEventsMask; + TInt idx = iCallBacks.Count(); + while(idx-- && eventsToFind) + { + TInt32 currentEvent = iCallBacks[idx].iEventMask; + if (currentEvent & aEvent) + { + TNotificationBase* notifBase = (TNotificationBase*) iCallBacks[idx].iCallBackClientParam; + if (notifBase && notifBase->iStatus && iCallBacks[idx].iScreenNumber == aScreenNumber) + { + TInt callBackOperation = (aOperation == EDefaultOperation) ? currentEvent : ESOWF_ObserverCheckVisible; + eventsToFind &= ~currentEvent; + switch (currentEvent) + { + case ESOWF_EventAvailable: + Available(callBackOperation, aSerialNumber, NULL, iCallBacks[idx].iCallBackClientParam, aReturnMask); + break; + + case ESOWF_EventDisplayed: + Displayed(callBackOperation, aSerialNumber, NULL, iCallBacks[idx].iCallBackClientParam, aReturnMask); + break; + + case ESOWF_EventDisplayedX: + DisplayedXTimes(callBackOperation, aSerialNumber, NULL, iCallBacks[idx].iCallBackClientParam, aReturnMask); + break; + + default: + break; + } + } + } + } + NFLOG(("### EXIT CSurfaceStream::ProcessNotifications()")); + } + +TInt CSurfaceStream::CheckBufferNumber(TInt aBuffer, + TRequestStatus* aStatusDisplayed, + TRequestStatus* aStatusDispXTimes, + TRequestStatus* aStatusConsumed) + { + if (aBuffer < 0 || aBuffer >= iInfo.iBuffers) + { + if (aStatusConsumed) + { + User::RequestComplete(aStatusConsumed, KErrArgument); + } + if (aStatusDisplayed) + { + User::RequestComplete(aStatusDisplayed, KErrArgument); + } + if (aStatusDispXTimes) + { + User::RequestComplete(aStatusDispXTimes, KErrArgument); + } + return KErrArgument; + } + else + { + return KErrNone; + } + } + +void CSurfaceStream::Available(TInt32 aEvent, + TInt32 aSerialNumber, + ContentUpdatedParams* aParams, + void* aCallBackData, + TInt32* aReturnMask) + { + (void) aReturnMask; + NFLOG(("### ENTER CSurfaceStream::Available aEvent(0x%x) aSerialNumber(0x%x) " + "aParams(0x%x) aCallBackData(0x%x) aReturnMask(0x%x)", + aEvent, aSerialNumber, aParams, aCallBackData, aReturnMask)); + + TNotificationAvailable* callBackData = (TNotificationAvailable*) aCallBackData; + if (!callBackData) + { + return; + } + + switch(aEvent) + { + case ESOWF_ObserverProcessing: + NFLOG(("###CSurfaceStream::Available ESOWF_ObserverProcessing")); + // when a new available notification request is issued by SUS, we have to: + // 1. Overflow the old request status (GCE behaviour) + // 2. Update the observer + // 3. If immediate availabilty chec if the old request status can be completed + // 4. Inform the composer about any active available notifications requests + { + if (aParams) + { + // let's check first for overflow conditions + // and overflow the oldest if exists (GCE behaviour) + if (callBackData->iStatus) + { + NFLOG(("###CSurfaceStream::Available ESOWF_ObserverProcessing Overflow")); + // oldest notifications is overflowed (like GCE behaviour) + RequestComplete(callBackData->iThreadId, callBackData->iStatus, callBackData->iGlobalIndex, KErrOverflow); + callBackData->iStatus = NULL; + callBackData->iThreadId = 0; + callBackData->iBufferNumber = -1; + } + + // propagate the new data + callBackData->iSerialNumber = aSerialNumber; + TBool multibuffered = iInfo.iBuffers > 1; + if (multibuffered) + { + callBackData->iStatus = callBackData->iNewStatus; + callBackData->iThreadId = callBackData->iNewThreadId; + callBackData->iBufferNumber = callBackData->iNewBufferNumber; + callBackData->iGlobalIndex = callBackData->iNewGlobalIndex; + } + else + { + callBackData->iStatus = aParams->iStatusConsumed; + callBackData->iThreadId = RThread().Id(); + callBackData->iBufferNumber = aParams->iBuffer; + callBackData->iGlobalIndex = aParams->iGlobalNotifications.iNewAvailableIdx; + } + + // the availability can be immediately completed if the + // visibility status is known and the composer is not composing at that momment + if (callBackData->iStatus && aParams->iImmediateAvailable) + { + NFLOG(("###CSurfaceStream::Available ESOWF_ObserverProcessing Immediate Available")); + if (iAcquiredWriteBuffer != WFC_INVALID_HANDLE) + { + iAcquiredWriteBuffer = BUFFER_WRITE_UPDATE_OVERWRITE; + } + + SetReadBufferIndex(aParams->iBuffer); + // immediate notification is possible because the context + // is not composing at this momment + if (aParams->iImmediateVisibility == SYM_CONTENT_NOT_VISIBLE) + { + RequestComplete(callBackData->iThreadId, callBackData->iStatus, callBackData->iGlobalIndex, KErrNotVisible); + } + else + { + RequestComplete(callBackData->iThreadId, callBackData->iStatus, callBackData->iGlobalIndex, KErrNone); + } + ResetCallBackData(callBackData, aEvent); + } + + if (multibuffered) + { + callBackData->iNewStatus = aParams->iStatusConsumed; + callBackData->iNewThreadId = RThread().Id(); + callBackData->iNewBufferNumber = aParams->iBuffer; + callBackData->iGlobalIndex = aParams->iGlobalNotifications.iNewAvailableIdx; + } + + // let the composer know that the Availability has to be analysed further + if (aReturnMask && callBackData->iStatus) + { + NFLOG(("###CSurfaceStream::Available ESOWF_ObserverProcessing *aReturnMask |= ESOWF_EventAvailable")); + *aReturnMask |= ESOWF_EventAvailable; + } + } + } + break; + + case ESOWF_EventAvailable: + NFLOG(("###CSurfaceStream::Available ESOWF_EventAvailable")); + if (callBackData->iStatus) + { + // if it is an event just added during composition, we wxpect the same serial number + RequestComplete(callBackData->iThreadId, callBackData->iStatus, callBackData->iGlobalIndex, KErrNone); + // clean the old reques notification related info + callBackData->iSerialNumber = aSerialNumber; + callBackData->iStatus = NULL; + callBackData->iThreadId = 0; + callBackData->iBufferNumber = -1; + } + break; + + case ESOWF_ObserverCheckVisible: + NFLOG(("###CSurfaceStream::Available ESOWF_ObserverCheckVisible")); + if (callBackData->iStatus) + { + // complete the old request status (standard GCE behaviour) + RequestComplete(callBackData->iThreadId, callBackData->iStatus, callBackData->iGlobalIndex, KErrNotVisible); + // clean the old reques notification related info + callBackData->iSerialNumber = aSerialNumber; + callBackData->iStatus = NULL; + callBackData->iThreadId = 0; + callBackData->iBufferNumber = -1; + } + break; + + case ESOWF_ObserverCancel: + { + NFLOG(("###CSurfaceStream::Available ESOWF_ObserverCancel")); + // cancel both requests if they are valid + RequestComplete(callBackData->iThreadId, callBackData->iStatus, callBackData->iGlobalIndex, KErrCancel); + RequestComplete(callBackData->iNewThreadId, callBackData->iNewStatus, callBackData->iGlobalIndex, KErrCancel); + ResetCallBackData(callBackData, aEvent); + } + break; + + default: + return; + } + NFLOG(("EXIT ###CSurfaceStream::Available()")); + } + + +void CSurfaceStream::Displayed(TInt32 aEvent, TInt32 aSerialNumber, ContentUpdatedParams* aParams, void* aCallBackData, TInt32* aReturnMask) + { + TInt notification = KErrNone; + (void) aReturnMask; + NFLOG(("### ENTER CSurfaceStream::Displayed aEvent(0x%x) aSerialNumber(0x%x) " + "aParams(0x%x) aCallBackData(0x%x) aReturnMask(0x%x)", + aEvent, aSerialNumber, aParams, aCallBackData, aReturnMask)); + TNotificationDisplayed* callBackData = (TNotificationDisplayed*) aCallBackData; + if (!callBackData) + { + return; + } + + switch(aEvent) + { + case ESOWF_ObserverProcessing: + NFLOG(("###CSurfaceStream::Displayed ESOWF_ObserverProcessing")); + // When a new available notification request is issued by SUS, we have to: + // 1. Overflow the previous request status + // 2. Update the observer + // 3. Inform the composer about any active available notifications requests + + if (callBackData->iStatus) + { + NFLOG(("###CSurfaceStream::Displayed ESOWF_ObserverProcessing Overflowing")); + RequestComplete(callBackData->iThreadId, callBackData->iStatus, callBackData->iGlobalIndex, KErrOverflow); + ResetCallBackData(callBackData, aEvent); + } + if (aParams && aParams->iStatusDisplayed) + { + __ASSERT_DEBUG(aParams->iTimeStamp, + (iRefCountMutex.Signal(),Panic(EOwfInvalidSUSDisplayedParameter))); + callBackData->iStatus = aParams->iStatusDisplayed; + callBackData->iThreadId = RThread().Id(); + callBackData->iBufferNumber = aParams->iBuffer; + callBackData->iSerialNumber = aSerialNumber; + callBackData->iTimeStamp = aParams->iTimeStamp; + callBackData->iGlobalIndex = aParams->iGlobalNotifications.iNewDisplayedIdx; + NFLOG(("###CSurfaceStream::Displayed iGlobalIndex(%d)", callBackData->iGlobalIndex)); + } + if (aReturnMask && callBackData->iStatus) + { + NFLOG(("###CSurfaceStream::Displayed ESOWF_ObserverProcessing *aReturnMask |= ESOWF_EventDisplayed")); + *aReturnMask |= ESOWF_EventDisplayed; + } + return; + + case ESOWF_EventDisplayed: + // this invoked by composer + NFLOG(("###CSurfaceStream::Displayed ESOWF_EventDisplayed")); + if (!callBackData->iStatus) + { + // no active notification, nothing to do + NFLOG(("###CSurfaceStream::Displayed ESOWF_EventDisplayed no active notifications")); + return; + } + // deffer for next composition the processing if the updated happended during a composition + if (callBackData->iSerialNumber == aSerialNumber && aReturnMask) + { + NFLOG(("###CSurfaceStream::Displayed ESOWF_EventDisplayed *aReturnMask |= ESOWF_EventDisplayed")); + *aReturnMask |= ESOWF_EventDisplayed; + return; + } + // complete the active request status + callBackData->iSerialNumber = aSerialNumber; + *callBackData->iTimeStamp = User::FastCounter(); + notification = KErrNone; + break; + + case ESOWF_ObserverCheckVisible: + // visibility check comming from composer + NFLOG(("###CSurfaceStream::Displayed ESOWF_ObserverCheckVisible")); + if (!callBackData->iStatus) + { + // deffer for next composition the processing if the updated happended during a composition + // or if no active notification, nothing to do + NFLOG(("###CSurfaceStream::Displayed ESOWF_ObserverCheckVisible = Not Visible")); + return; + } + notification = KErrNotVisible; + callBackData->iSerialNumber = aSerialNumber; + break; + + case ESOWF_ObserverCancel: + // cancel the active notification + NFLOG(("###CSurfaceStream::Displayed ESOWF_ObserverCancel")); + if (!callBackData->iStatus) + { + return; + } + notification = KErrCancel; + break; + + default: + return; + } + + RequestComplete(callBackData->iThreadId, callBackData->iStatus, callBackData->iGlobalIndex, notification); + ResetCallBackData(callBackData, aEvent); + NFLOG(("EXIT ###CSurfaceStream::Displayed()")); + } + +void CSurfaceStream::DisplayedXTimes(TInt32 aEvent, TInt32 aSerialNumber, ContentUpdatedParams* aParams, void* aCallBackData, TInt32* aReturnMask) + { + TInt notification = KErrNone; + + NFLOG(("### ENTER CSurfaceStream::DisplayedXTimes aEvent(0x%x) aSerialNumber(0x%x) " + "aParams(0x%x) aCallBackData(0x%x) aReturnMask(0x%x)", + aEvent, aSerialNumber, aParams, aCallBackData, aReturnMask)); + + TNotificationDisplayedX* callBackData = (TNotificationDisplayedX*) aCallBackData; + if (!callBackData) + { + return; + } + + switch(aEvent) + { + case ESOWF_ObserverProcessing: + // When a new available notification request is issued by SUS, we have to: + // 1. Overflow the previous request status + // 2. Update the observer + // 3. Inform the composer about any active available notifications requests + NFLOG(("###CSurfaceStream::DisplayedXTimes ESOWF_ObserverProcessing")); + if (callBackData->iStatus) + { + NFLOG(("###CSurfaceStream::DisplayedXTimes ESOWF_ObserverProcessing Overflowing")); + RequestComplete(callBackData->iThreadId, callBackData->iStatus, callBackData->iGlobalIndex, KErrOverflow); + ResetCallBackData(callBackData, aEvent); + } + if (aParams && aParams->iStatusDispXTimes) + { + __ASSERT_DEBUG(aParams->iDisplayedXTimes && *aParams->iDisplayedXTimes >= 1, + (iRefCountMutex.Signal(),Panic(EOwfInvalidSUSDisplayedXTimesParameter))); + callBackData->iStatus = aParams->iStatusDispXTimes; + callBackData->iThreadId = RThread().Id(); + callBackData->iBufferNumber = aParams->iBuffer; + callBackData->iSerialNumber = aSerialNumber; + callBackData->iCount = *aParams->iDisplayedXTimes; + callBackData->iGlobalIndex = aParams->iGlobalNotifications.iNewDisplayedXIdx; + } + + if (aReturnMask && callBackData->iStatus) + { + NFLOG(("###CSurfaceStream::DisplayedXTimes ESOWF_ObserverProcessing *aReturnMask |= ESOWF_EventDisplayedX")); + *aReturnMask |= ESOWF_EventDisplayedX; + } + return; + + case ESOWF_EventDisplayedX: + NFLOG(("###CSurfaceStream::DisplayedXTimes ESOWF_EventDisplayedX")); + if (!callBackData->iStatus) + { + // no active notification, nothing to do + return; + } + + // deffer for next composition the processing if the updated happended during a composition + if (callBackData->iSerialNumber == aSerialNumber) + { + if (aReturnMask) + { + NFLOG(("###CSurfaceStream::DisplayedXTimes ESOWF_EventDisplayedX *aReturnMask |= ESOWF_EventDisplayedX")); + *aReturnMask |= ESOWF_EventDisplayedX; + } + return; + } + + callBackData->iSerialNumber = aSerialNumber; + + // complete the active request status + if (callBackData->iCount > 1) + { + // inform the composer a new notification is needed + callBackData->iCount--; + if (aReturnMask) + { + NFLOG(("###CSurfaceStream::DisplayedXTimes ESOWF_EventDisplayedX *aReturnMask |= ESOWF_EventDisplayedX iCount(%d)", callBackData->iCount)); + *aReturnMask |= ESOWF_EventDisplayedX; + } + return; + } + + NFLOG(("###CSurfaceStream::DisplayedXTimes ESOWF_EventDisplayedX iCount(%d)", callBackData->iCount)); + notification = KErrNone; + break; + + case ESOWF_ObserverCheckVisible: + NFLOG(("###CSurfaceStream::DisplayedXTimes ESOWF_ObserverCheckVisible")); + // visibility check comming from composer + if (!callBackData->iStatus || + callBackData->iSerialNumber == aSerialNumber) + { + // deffer for next composition the processing if the updated happended during a composition + // or if no active notification, nothing to do + return; + } + callBackData->iSerialNumber = aSerialNumber; + notification = KErrNotVisible; + break; + + case ESOWF_ObserverCancel: + // cancel the active notification + NFLOG(("###CSurfaceStream::DisplayedXTimes ESOWF_ObserverCancel")); + if (!callBackData->iStatus) + { + return; + } + notification = KErrCancel; + break; + + default: + return; + } + + RequestComplete(callBackData->iThreadId, callBackData->iStatus, callBackData->iGlobalIndex, notification); + ResetCallBackData(callBackData, aEvent); + NFLOG(("EXIT ###CSurfaceStream::DisplayedXTimes()")); + } + +void CSurfaceStream::ResetCallBackData(void* aCallBackData, + TInt32 aEvent) + { + switch (aEvent) + { + case ESOWF_EventAvailable: + { + TNotificationAvailable* available = (TNotificationAvailable*) aCallBackData; + available->iStatus = NULL; + available->iThreadId = 0; + available->iBufferNumber = -1; + available->iGlobalIndex = KInvalidIndex; + available->iNewBufferNumber = -1; + available->iNewStatus = NULL; + available->iNewThreadId = 0; + available->iNewGlobalIndex = KInvalidIndex; + } + break; + + case ESOWF_EventDisplayed: + { + TNotificationDisplayed* displayed = (TNotificationDisplayed*) aCallBackData; + displayed->iStatus = NULL; + displayed->iThreadId = 0; + displayed->iBufferNumber = -1; + displayed->iTimeStamp = NULL; + displayed->iGlobalIndex = KInvalidIndex; + } + break; + + case ESOWF_EventDisplayedX: + { + TNotificationDisplayedX* displayed = (TNotificationDisplayedX*) aCallBackData; + displayed->iStatus = NULL; + displayed->iThreadId = 0; + displayed->iBufferNumber = -1; + displayed->iCount = 0; + displayed->iGlobalIndex = KInvalidIndex; + } + break; + + default: + break; + } + } + +void CSurfaceStream::CancelNotifications() + { + NFLOG(("ENTER ###CSurfaceStream::CancelNotifications()")); + TInt cancelEvents = ESOWF_AllEventsMask; + RemoveObserver(cancelEvents, NULL); + NFLOG(("EXIT ###CSurfaceStream::CancelNotifications()")); + } + +TInt CSurfaceStream::Stride(TInt aWidth, TUidPixelFormat aPixelFormat) + { + + TInt bytesPerPixel = BytesPerPixel(aPixelFormat); + + if (bytesPerPixel >= 0) + { + return bytesPerPixel * aWidth; // number of bytes between start of one line and start of next + } + else + { + return (aWidth-(bytesPerPixel+1)) / (-bytesPerPixel); + } + } + +void CSurfaceStream::SetFlipState(TBool aFlip) + { + Guard g1(iRefCountMutex); + if (aFlip) + { + iNewFlip = EFlippedTargetFlipped; + } + else + { + iNewFlip = EFlippedTargetNormal; + } + }