--- /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 <e32base.h>
+#include <graphics/suerror.h>
+#include <graphics/surfacetypes.h>
+#include <hal.h>
+#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<TInt>(this);
+ iStreamProxySurfaceId.iInternal[TSurfaceId::TSurfaceUsage::ETypeClassField]=
+ TSurfaceId::EStreamHandle<<TSurfaceId::TSurfaceUsage::ETypeClassShift;
+ }
+
+CSurfaceStream::ContentUpdatedParams::ContentUpdatedParams(TInt aBuffer,
+ TRequestStatus* aStatusDisplayed, TUint32* aTimeStamp,
+ TRequestStatus* aStatusDispXTimes, TInt* aDisplayedXTimes,
+ TRequestStatus* aStatusConsumed, const TRegion* aRegion,
+ TBool aImmediateAvailable, TInt32 aImmediateVisibility,
+ const TNewGlobalNotifications& aGlobalNotifications):
+iBuffer(aBuffer),
+iStatusDisplayed(aStatusDisplayed),
+iTimeStamp(aTimeStamp),
+iStatusDispXTimes(aStatusDispXTimes),
+iDisplayedXTimes(aDisplayedXTimes),
+iStatusConsumed(aStatusConsumed),
+iRegion(aRegion),
+iImmediateAvailable(aImmediateAvailable),
+iImmediateVisibility(aImmediateVisibility),
+iGlobalNotifications(aGlobalNotifications)
+ {
+
+ }
+
+CSurfaceStream::~CSurfaceStream()
+ {
+ // Cancel any outstanding notifications
+ CancelNotifications();
+ iCallBacks.Close();
+ iGlobalNotifications.Close();
+ iBufferChunk.Close();
+
+ if (!iSurfaceId.IsNull() && iSurfaceId.Type() == TSurfaceTypes::ESurfaceManagerSurface)
+ {
+ TRAP_IGNORE(GetSingletonL().SurfaceManager().CloseSurface(iSurfaceId));
+ }
+
+ iRefCountMutex.Close();
+ iCallBacksMutex.Close();
+ delete [] iBufferInfo;
+ }
+
+CSurfaceStream* CSurfaceStream::NewLC(const TSurfaceId& aId)
+ {
+ CSurfaceStream* self = new (ELeave)CSurfaceStream();
+ CleanupStack::PushL(self);
+ self->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<TInt>(this);
+ iStreamProxySurfaceId.iInternal[TSurfaceId::TSurfaceUsage::ETypeClassField]=
+ TSurfaceId::EStreamHandle<<TSurfaceId::TSurfaceUsage::ETypeClassShift;
+
+ User::LeaveIfError(stream.SurfaceManager().OpenSurface(aId));
+ iSurfaceId = aId;
+ User::LeaveIfError(stream.SurfaceManager().SurfaceInfo(iSurfaceId, aInfoBuf));
+ break;
+ }
+ case TSurfaceId::EScreenSurface:
+ {
+ // DSA surface only has one buffer
+ aInfoBuf().iBuffers = 1;
+
+ TInt screenId = aId.iInternal[TSurfaceId::TScreenSurfaceUsage::EScreenField];
+ TInt width;
+ User::LeaveIfError(HAL::Get(screenId, HALData::EDisplayXPixels, width));
+
+ TInt height;
+ User::LeaveIfError(HAL::Get(screenId, HALData::EDisplayYPixels, height));
+
+ aInfoBuf().iSize = TSize(width, height);
+
+ TInt bpp = 0;
+ User::LeaveIfError(HAL::Get(screenId, HALData::EDisplayBitsPerPixel, bpp));
+
+ TUidPixelFormat pixelFormat = static_cast<TUidPixelFormat> (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<CSurfaceStream*>(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<khronos_int32_t>(iInfo.iSize.iHeight);
+ }
+ else
+ {
+ *aWidth = static_cast<khronos_int32_t>(iInfo.iSize.iWidth);
+ }
+ }
+
+ if (aHeight)
+ {
+ if (iFlipState == EFlippedTargetFlipped)
+ {
+ *aHeight = static_cast<khronos_int32_t>(iInfo.iSize.iWidth);
+ }
+ else
+ {
+ *aHeight = static_cast<khronos_int32_t>(iInfo.iSize.iHeight);
+ }
+ }
+ if (aStride)
+ {
+ if (iFlipState == EFlippedTargetFlipped)
+ {
+ *aStride = Stride(iInfo.iSize.iHeight, iInfo.iPixelFormat);
+ }
+ else
+ {
+ *aStride = static_cast<khronos_int32_t>(iInfo.iStride);
+ }
+ }
+ if (aFormat)
+ {
+ *aFormat=iInfo.iPixelFormat;
+ }
+ if (aPixelSize)
+ {
+ *aPixelSize = static_cast<khronos_int32_t>(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<void*>(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<SymbianStreamBuffer>(aIndex + BUFFER_READ_HANDLE_BASE);
+ }
+
+SymbianStreamBuffer CSurfaceStream::IndexToWriteHandle(TInt aIndex)
+ {
+ return static_cast<SymbianStreamBuffer>(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<iInfo.iBuffers,User::Invariant());
+ return retVal;
+ }
+
+
+
+
+void CSurfaceStream::RequestComplete(TThreadId& aThreadId, TRequestStatus*& aRequestStatus, TInt& aGlobalIndexArray, TInt aStatus)
+ {
+ if (aRequestStatus)
+ {
+ if (aGlobalIndexArray != KInvalidIndex)
+ {
+ TGlobalNotification& globalNotification = iGlobalNotifications[aGlobalIndexArray];
+ --globalNotification.iPendingNotifications;
+ switch (aStatus)
+ {
+ case KErrNone:
+ globalNotification.iCompletedOkNotifications++;
+ break;
+ case KErrOverflow:
+ globalNotification.iOverflowedNotifications++;
+ break;
+ case KErrCancel:
+ globalNotification.iCanceledNotifications++;
+ break;
+ case KErrNotVisible:
+ globalNotification.iNotVisibleNotifications++;
+ break;
+ default:
+ globalNotification.iOtherNotifications++;
+ }
+ NFLOG(("### CSurfaceStream::RequestComplete globalRequestStatus[%d] iPendingNotifications(%d) "
+ "iCompletedOkNotifications(%d)"
+ "iOverflowedNotifications(%d)"
+ "iCanceledNotifications(%d)"
+ "iNotVisibleNotifications(%d)"
+ "iOtherNotifications(%d)"
+ "requestStatus(%p)",
+ aGlobalIndexArray,
+ globalNotification.iPendingNotifications,
+ globalNotification.iCompletedOkNotifications,
+ globalNotification.iOverflowedNotifications,
+ globalNotification.iCanceledNotifications,
+ globalNotification.iNotVisibleNotifications,
+ globalNotification.iOtherNotifications,
+ aStatus));
+
+ if (globalNotification.iStatus && globalNotification.iPendingNotifications == 0)
+ {
+ TInt status;
+ if (globalNotification.iCompletedOkNotifications > 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;
+ }
+ }