Merge 1. Pull in cpp files in the performance enhanced Khronos RI OVG files which are newly added. I've ignored platform-specific cpp files for linux, macosx, and null operating systems because this local solution has its own platform glue (i.e. facility to target Bitmaps but no full windowing support). I've ignored sfEGLInterface.cpp because this is used as a bridge to go from EGL to Nokia's Platsim which offers an EGL service. That's not relevant to this implementation because this is ARM side code, not Intel side. I just left a comment to sfEGLInterface.cpp in case we need to pick up this later on. The current code compiles on winscw. Prior to this fix, the code works on winscw, and can launch the SVG tiger (tiger.exe). That takes about 20 seconds to render. I hope to always be able to show this icon on each commit, and the plan is for the render time to reduce with this series of submissions. On this commit, the tiger renders ok in 20 seconds.
// Copyright (c) 2005-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:
// The client-side representation of a WsGraphic artwork
//
//
#include <w32std.h>
#include "../SERVER/w32cmd.h"
#include "w32comm.h"
#include "CLIENT.H"
#include <s32mem.h>
#include <Graphics/WSGRAPHICDRAWERINTERFACE.H>
NONSHARABLE_STRUCT(CWsGraphic::CPimpl): public CBase, public MWsClientClass
/** @internalComponent @released */
{
friend class CWsGraphic;
enum
{
/** is registered in the graphic manager's array */
ERegistered = 0x01,
/** has a peer CWsGraphicDrawer on the server */
EHasPeer = 0x02
};
CPimpl(CWsGraphic& aGraphic);
~CPimpl();
void ConstructL(); //LeaveScan: Member of macroised structure declaration.
CManager* iManager;
TInt WriteCreateGraphic(TWsClCmdCreateGraphic& aCreateGraphic,const TDesC8& aData,TInt aWsHandle) const;
CWsGraphic& iGraphic;
TWsGraphicId iId;
TUint iFlags;
MWsObjectProvider* iExt;
};
LOCAL_C void MWsGraphicMessageAllocRelease(TAny* aAny)
{
MWsGraphicMessageAlloc::MBuffer* buf = static_cast<MWsGraphicMessageAlloc::MBuffer*>(aAny);
if(buf)
{
buf->Release();
}
}
NONSHARABLE_CLASS(CWsGraphic::CManager): private CActive, public RWsSession
/** Client-side manager singleton for marshalling messages for all CWsGraphics owned by a client
@publishedAll
@released
*/ {
public:
static CManager* StaticL(); //LeaveScan: Member of macroised structure declaration.
// used by CWsGraphic
void AddL(CWsGraphic* aGraphic); //LeaveScan: Member of macroised structure declaration.
void Replace(CWsGraphic* aGraphic);
void Remove(CWsGraphic* aGraphic);
CWsGraphic* Find(const TWsGraphicId& aId);
void Inc();
void Dec();
RWsBuffer* Buffer();
void ScheduleFlush();
private:
CManager();
~CManager();
void ConstructL(); //LeaveScan: Member of macroised structure declaration.
void Queue();
void RunL(); //LeaveScan: Member of macroised structure declaration.
void DoCancel();
static TInt GraphicCompare(const CWsGraphic& aFirst,const CWsGraphic& aSecond);
static TInt FlushOnIdle(TAny* aArg);
private:
TInt iRefCount;
RPointerArray<CWsGraphic> iArray;
CIdle* iFlusher;
TBool iFlushScheduled;
};
// TWsGraphicId \\\\\\\\\\\\\\\\\\\\\\\\
EXPORT_C TWsGraphicId::TWsGraphicId(TUid aUid):
/** Construct a UID
@param aUid UID of the graphic artwork.
@publishedAll @released
*/ iFlags(EWsGraphicIdUid), iId(aUid.iUid)
{
}
EXPORT_C TWsGraphicId::TWsGraphicId(TInt aId):
/** Construct a transient Id
@publishedAll @released
*/ iFlags(EWsGraphicIdTransient), iId(aId)
{
}
/**
Copy constructor.
@param aCopy Graphic artwork Id.
*/
EXPORT_C TWsGraphicId::TWsGraphicId(const TWsGraphicId& aCopy):
iFlags(aCopy.iFlags), iId(aCopy.iId)
{
}
EXPORT_C TUid TWsGraphicId::Uid() const
/** Returns UID.
@return UID of graphic artwork. KNullUid if graphic artwork is transient.
@publishedAll @released
*/ {
if(IsUid())
{
return TUid::Uid(iId);
}
return KNullUid;
}
EXPORT_C TBool TWsGraphicId::IsUid() const
/** Identifies whether graphic artwork is non-transient.
@return ETrue if graphic artwork is non-transient.
@publishedAll @released
*/ {
return (iFlags & EWsGraphicIdUid);
}
EXPORT_C void TWsGraphicId::Set(TUid aUid)
/** Set to be a UID
@publishedAll @released
*/ {
iId = aUid.iUid;
iFlags = EWsGraphicIdUid;
}
EXPORT_C TInt TWsGraphicId::Id() const
/** Returns the transient Id.
@return Id of transient graphic artwork. Zero if graphic artwork is non-transient.
@publishedAll @released
*/ {
if(IsId())
{
return iId;
}
return 0;
}
EXPORT_C TBool TWsGraphicId::IsId() const
/** Identifies whether graphic artwork is transient.
@return ETrue if graphic artwork is transient.
@publishedAll @released
*/ {
return (iFlags & EWsGraphicIdTransient);
}
EXPORT_C void TWsGraphicId::Set(TInt aId)
/** Set to be a transient Id
@publishedAll @released
*/ {
iId = aId;
iFlags = EWsGraphicIdTransient;
}
EXPORT_C TInt TWsGraphicId::Compare(const TWsGraphicId& aOther) const
/** Compares another Id with this one.
@return 0 if the other Id is identical, else -1 if the other Id is to greater than or 1 if the other Id is less than
@publishedAll @released
*/ {
if(iId < aOther.iId)
{
return -1;
}
else if(iId > aOther.iId)
{
return 1;
}
// else we have to compare the iIsUid flag too; again, expect it to be a match 99.99% of these times
else if(IsUid() == aOther.IsUid())
{
return 0;
}
// collisions of id but not iIsUid are going to be really really rare
else if(IsUid())
{
return 1;
}
else
{
return -1;
}
}
// CWsGraphicManager \\\\\\\\\\\\\\\\\\\\\\\\
CWsGraphic::CManager* CWsGraphic::CManager::StaticL()
{
CManager* singleton = RWsBuffer::WsGraphicManager();
if(!singleton)
{
singleton = new(ELeave) CManager;
CleanupStack::PushL(singleton);
singleton->ConstructL();
CleanupStack::Pop(singleton);
__ASSERT_DEBUG(singleton == RWsBuffer::WsGraphicManager(),Panic(EW32PanicGraphicInternal));
}
return singleton;
}
CWsGraphic::CManager::~CManager()
{
__ASSERT_DEBUG(!ResourceCount(),Panic(EW32PanicGraphicInternal));
__ASSERT_DEBUG(!iArray.Count(),Panic(EW32PanicGraphicOrphaned));
Close();
__ASSERT_DEBUG(!RWsBuffer::WsGraphicManager(),Panic(EW32PanicGraphicInternal));
iArray.Close();
delete iFlusher;
}
CWsGraphic::CManager::CManager(): CActive(CActive::EPriorityStandard)
{
}
void CWsGraphic::CManager::ConstructL()
{
User::LeaveIfError(Connect());
iBuffer->SetWsGraphicManager(this);
CActiveScheduler::Add(this);
iFlusher = CIdle::NewL(CActive::EPriorityIdle);
}
void CWsGraphic::CManager::Inc()
{
iRefCount++;
}
void CWsGraphic::CManager::Dec()
{
if(!--iRefCount)
{
delete this;
}
}
RWsBuffer* CWsGraphic::CManager::Buffer()
{
return iBuffer;
}
// used by CWsGraphic
void CWsGraphic::CManager::AddL(CWsGraphic* aGraphic)
/** Leaves if the graphic couldn't be added to the list
@internalComponent @released */
{
__ASSERT_ALWAYS(aGraphic && aGraphic->iPimpl,Panic(EW32PanicGraphicInternal));
__ASSERT_ALWAYS(aGraphic->Id().IsId() || aGraphic->Id().IsUid(),Panic(EW32PanicGraphicInternal));
__ASSERT_ALWAYS(!(aGraphic->iPimpl->iFlags & CWsGraphic::CPimpl::ERegistered),Panic(EW32PanicGraphicInternal));
iArray.InsertInOrderL(aGraphic,GraphicCompare);
__ASSERT_ALWAYS(0 <= iArray.FindInOrder(aGraphic,GraphicCompare),Panic(EW32PanicGraphicInternal));
aGraphic->iPimpl->iFlags |= CWsGraphic::CPimpl::ERegistered;
Queue();
}
void CWsGraphic::CManager::Replace(CWsGraphic* aGraphic)
/** @internalComponent @released */
{
__ASSERT_ALWAYS(aGraphic && aGraphic->iPimpl,Panic(EW32PanicGraphicInternal));
__ASSERT_ALWAYS(!(aGraphic->iPimpl->iFlags & CWsGraphic::CPimpl::ERegistered),Panic(EW32PanicGraphicInternal));
__ASSERT_ALWAYS(aGraphic->Id().IsId() || aGraphic->Id().IsUid(),Panic(EW32PanicGraphicInternal));
const TInt idx = iArray.FindInOrder(aGraphic,GraphicCompare);
__ASSERT_ALWAYS(0 <= idx,Panic(EW32PanicGraphicInternal));
__ASSERT_ALWAYS(iArray[idx]->iPimpl->iFlags & CWsGraphic::CPimpl::ERegistered,Panic(EW32PanicGraphicInternal));
iArray[idx]->iPimpl->iFlags &= ~CWsGraphic::CPimpl::ERegistered;
iArray[idx] = aGraphic;
iArray[idx]->iPimpl->iFlags |= CWsGraphic::CPimpl::ERegistered;
Queue();
}
void CWsGraphic::CManager::Remove(CWsGraphic* aGraphic)
/** @internalComponent @released */
{
__ASSERT_ALWAYS(aGraphic && aGraphic->iPimpl,Panic(EW32PanicGraphicInternal));
__ASSERT_ALWAYS(aGraphic->Id().IsId() || aGraphic->Id().IsUid(),Panic(EW32PanicGraphicInternal));
__ASSERT_ALWAYS(aGraphic->iPimpl->iFlags & CWsGraphic::CPimpl::ERegistered,Panic(EW32PanicGraphicInternal));
const TInt idx = iArray.FindInOrder(aGraphic,GraphicCompare);
__ASSERT_ALWAYS(0 <= idx,Panic(EW32PanicGraphicInternal));
iArray[idx]->iPimpl->iFlags &= ~CWsGraphic::CPimpl::ERegistered;
iArray.Remove(idx);
if(!iArray.Count())
{
Cancel();
}
}
CWsGraphic* CWsGraphic::CManager::Find(const TWsGraphicId& aId)
/** Find the active artwork identified by the Id
@return NULL if no active artwork has the Id
@publishedAll @released */
{
/* RPointerArray can only FindInOrder other T*, which is a needless shame. Therefore this search is
dumb sequential */
const TInt count = iArray.Count();
for(TInt i=0; i<count; i++)
{
CWsGraphic* graphic = iArray[i];
__ASSERT_ALWAYS(graphic && graphic->iPimpl && (graphic->iPimpl->iFlags & CWsGraphic::CPimpl::ERegistered),Panic(EW32PanicGraphicInternal));
const TWsGraphicId& candidate = graphic->Id();
if(0 == candidate.Compare(aId))
{
// found
__ASSERT_DEBUG(i == iArray.FindInOrder(graphic,GraphicCompare),Panic(EW32PanicGraphicInternal));
return graphic;
}
}
// not found
return NULL;
}
void CWsGraphic::CManager::Queue()
{
if(!IsActive())
{
GraphicMessageReady(&iStatus);
SetActive();
}
}
void CWsGraphic::CManager::RunL()
{
if(0 < iStatus.Int())
{
// a message to fetch!
const TInt msgLen = iStatus.Int();
TPtr8 buf(NULL,0);
MWsGraphicMessageAlloc* allocator = NULL;
MWsGraphicMessageAlloc::MBuffer* theirBuf = NULL;
HBufC8* ourBuf = HBufC8::New(msgLen);
if(ourBuf)
{
CleanupStack::PushL(ourBuf);
buf.Set(ourBuf->Des());
}
else // try to see if the destination CWsGraphic can allocate for us
{
const TInt handle = GraphicFetchHeaderMessage();
CWsGraphic* dest = reinterpret_cast<CWsGraphic*>(handle & ~0x03);
// check if it's valid
if(KErrNotFound != iArray.Find(dest) && dest->iPimpl && dest->iPimpl->iExt)
{
// check if the client is able to alloc memory for us
allocator = dest->iPimpl->iExt->ObjectInterface<MWsGraphicMessageAlloc>();
if(allocator)
{
// allocate memory
theirBuf = allocator->Alloc(msgLen);
if(theirBuf)
{
CleanupStack::PushL(TCleanupItem(MWsGraphicMessageAllocRelease,theirBuf));
buf.Set(theirBuf->Buffer());
}
}
}
}
if(!ourBuf && !theirBuf)
{
GraphicMessageCancel();
GraphicAbortMessage(KErrNoMemory);
}
else
{
GetGraphicMessage(buf);
// decode header and body
RDesReadStream in(buf);
in.PushL();
const TInt header = in.ReadInt32L();
__ASSERT_COMPILE(sizeof(header) == sizeof(TInt32));
const TInt clientHandle = (header & ~0x03);
const TInt msgType = (header & 0x03);
const TPtr8 body = buf.MidTPtr(sizeof(header));
// dispatch
CWsGraphic* dest = (CWsGraphic*)clientHandle;
if(KErrNotFound != iArray.Find(dest))
{
switch(msgType)
{
case EWsGraphMessageTypeUser:
dest->HandleMessage(body);
break;
default:
Panic(EW32PanicGraphicInternal);
}
}
// done
in.Pop();
}
if(ourBuf)
{
CleanupStack::PopAndDestroy(ourBuf);
}
else if(theirBuf)
{
CleanupStack::PopAndDestroy(theirBuf);
}
// done, wait for next message
Queue();
}
}
void CWsGraphic::CManager::DoCancel()
{
GraphicMessageCancel();
}
TInt CWsGraphic::CManager::GraphicCompare(const CWsGraphic& aFirst,const CWsGraphic& aSecond)
/** Compares two graphics for id equality
@internalComponent
@released
*/ {
return aFirst.Id().Compare(aSecond.Id());
}
void CWsGraphic::CManager::ScheduleFlush()
/** Request to schedule flush when idle
@internalComponent
@released
*/
{
if (iFlushScheduled)
return;
iFlushScheduled = ETrue;
iFlusher->Start(TCallBack(CWsGraphic::CManager::FlushOnIdle,this));
}
TInt CWsGraphic::CManager::FlushOnIdle(TAny* aArg)
/** Flush buffer when idle and there is outstanding data in it
@internalComponent
@released
*/
{
CWsGraphic::CManager* mgr = reinterpret_cast<CWsGraphic::CManager*>(aArg);
if (mgr)
{
mgr->iFlushScheduled = EFalse;
if (mgr->iBuffer && !mgr->iBuffer->IsEmpty())
mgr->iBuffer->Flush();
}
return 0; // complete
}
// CWsGraphic::CPimpl \\\\\\\\\\\\\\\\\\\\\\\\
CWsGraphic::CPimpl::CPimpl(CWsGraphic& aGraphic):
iGraphic(aGraphic), iId(TWsGraphicId::EUninitialized)
{
}
CWsGraphic::CPimpl::~CPimpl()
{
if(iManager)
{
iManager->Dec();
}
}
void CWsGraphic::CPimpl::ConstructL()
{
iManager = CManager::StaticL();
iManager->Inc();
iBuffer = iManager->Buffer();
}
TInt CWsGraphic::CPimpl::WriteCreateGraphic(TWsClCmdCreateGraphic& aCreateGraphic,const TDesC8& aData,TInt aWsHandle) const
/** Writes the CreateGraphic message to the server. If the data will not fit in the buffer, uses remote-read
@internalComponent @released */
{
aCreateGraphic.iDataLen = aData.Size();
aCreateGraphic.iRemoteReadData = ((aData.Size()+sizeof(aCreateGraphic))>(TInt)(iBuffer->BufferSize()-sizeof(TWsCmdHeader)));
if(aCreateGraphic.iRemoteReadData)
{
return iBuffer->WriteReplyByProvidingRemoteReadAccess(aWsHandle,EWsClOpCreateGraphic,&aCreateGraphic,sizeof(aCreateGraphic),&aData);
}
else if(aCreateGraphic.iDataLen)
{
return iBuffer->WriteReplyWs(&aCreateGraphic,sizeof(aCreateGraphic),aData.Ptr(),aData.Size(),EWsClOpCreateGraphic);
}
else
{
return iBuffer->WriteReplyWs(&aCreateGraphic,sizeof(aCreateGraphic),EWsClOpCreateGraphic);
}
}
// CWsGraphic \\\\\\\\\\\\\\\\\\\\\\\\
/**
Default Constructor.
*/
EXPORT_C CWsGraphic::CWsGraphic()
{
}
/**
Destructor.
*/
EXPORT_C CWsGraphic::~CWsGraphic()
{
Destroy();
delete iPimpl;
}
/**
Completes construction of the baseclass. All the overloaded BaseConstructL() methods
should invoke this method to complete the construction of the baseclass.
*/
void CWsGraphic::BaseConstructL()
{
iPimpl = new(ELeave) CPimpl(*this);
iPimpl->ConstructL();
}
EXPORT_C void CWsGraphic::BaseConstructL(TUid aUid,TUid aType,const TDesC8& aData)
/**
Constructs a piece of non-transient graphic artwork.
@capability ProtServ
@param aUid Graphic artwork UID.
@param aType Graphic artwork type.
@param aData User specific data.
*/ {
BaseConstructL();
TWsClCmdCreateGraphic createGraphic;
createGraphic.iFlags = EWsGraphicIdUid;
createGraphic.iId = aUid.iUid;
createGraphic.iType = aType;
createGraphic.iClientHandle = (TInt)this;
TInt ret = iPimpl->WriteCreateGraphic(createGraphic,aData,iPimpl->iManager->WsHandle());
User::LeaveIfError(ret);
iPimpl->iWsHandle=ret;
iPimpl->iId = aUid;
iPimpl->iFlags = CPimpl::EHasPeer;
iPimpl->iManager->AddL(this);
}
EXPORT_C void CWsGraphic::BaseConstructL(TUid aType,const TDesC8& aData)
/**
Constructs a piece of transient graphic artwork.
@param aType Graphic artwork type.
@param aData User specific data.
*/
{
BaseConstructL();
TWsClCmdCreateGraphic createGraphic;
createGraphic.iFlags = EWsGraphicIdTransient;
createGraphic.iId = 0;
createGraphic.iType = aType;
createGraphic.iClientHandle = (TInt)this;
TInt ret = iPimpl->WriteCreateGraphic(createGraphic,aData,iPimpl->iManager->WsHandle());
User::LeaveIfError(ret);
iPimpl->iWsHandle = ret;
// fetch id from server
TPckgBuf<TWsClCmdGdGetId> cmd;
User::LeaveIfError(iPimpl->WriteReplyP(TWriteDescriptorType(&cmd),EWsGdOpGetGraphicId));
if(cmd().iIsUid)
{
__DEBUG_ONLY(Panic(EW32PanicGraphicInternal));
User::Leave(KErrGeneral);
}
iPimpl->iId = cmd().iId;
iPimpl->iFlags = CPimpl::EHasPeer;
iPimpl->iManager->AddL(this);
}
EXPORT_C void CWsGraphic::BaseConstructL(const TWsGraphicId& aReplace,TUid aType,const TDesC8& aData)
/**
Atomically replace the artwork that already exists with this artwork.
If failure to properly construct the replacement artwork occurs, the replacee artwork will remain
@param aReplace Graphic artwork which will be replaced.
@param aType New graphic artwork type.
@param aData User specific data.
*/
{
BaseConstructL();
CWsGraphic* dup = iPimpl->iManager->Find(aReplace);
if(!dup || !dup->iPimpl)
{
Panic(EW32PanicGraphicInternal);
}
const TUint flags = aReplace.IsUid()?EWsGraphicIdUid:EWsGraphicIdTransient;
TWsClCmdCreateGraphic createGraphic;
createGraphic.iFlags = EWsGraphicReplace|flags;
createGraphic.iId = aReplace.IsUid()?aReplace.Uid().iUid:aReplace.Id();
createGraphic.iType = aType;
createGraphic.iClientHandle = (TInt)this;
TInt ret = iPimpl->WriteCreateGraphic(createGraphic,aData,iPimpl->iManager->WsHandle());
if(0 > ret)
{
User::Leave(ret);
}
iPimpl->iWsHandle = ret;
iPimpl->iId = aReplace;
iPimpl->iFlags = CPimpl::EHasPeer;
iPimpl->iManager->Replace(this);
// when WriteCreateGraphic succeeds, the replacee drawer has already been destroyed serverside
// so this cleanup is not quite the same as Destroy(), as it doesn't free server side
// coverity[var_deref_op]
dup->iPimpl->iWsHandle = 0;
dup->OnReplace();
dup->iPimpl->iFlags &= ~CPimpl::EHasPeer;
}
/**
Shares the graphic artwork with all the client sessions.
Sharing globally trumps explicit shares.
@return KErrNone if the graphic is globally shared, else one of the system-wide error codes.
*/
EXPORT_C TInt CWsGraphic::ShareGlobally()
{
if(!IsActive())
{
return KErrNotReady;
}
return iPimpl->WriteReply(EWsGdOpShareGlobally);
}
/**
Prevents this graphic artwork from being shared with all the client sessions.
A graphic artwork that isn't shared explicitly is only available to clients it
has been explicitly shared with using Share().
@return KErrNone if the graphic is not globally shared, else one of the system-wide error codes.
*/
EXPORT_C TInt CWsGraphic::UnShareGlobally()
{
if(!IsActive())
{
return KErrNotReady;
}
return iPimpl->WriteReply(EWsGdOpUnShareGlobally);
}
/**
Explicitly shares this graphic artwork with client sessions with the specified Secure ID.
@param aClientId the Secure ID of the client sessions to share with.
@return KErrNone If the graphic artwork was shared, else one of the system-wide error codes.
*/
EXPORT_C TInt CWsGraphic::Share(TSecureId aClientId)
{
if(!IsActive())
{
return KErrNotReady;
}
return iPimpl->WriteReply(&aClientId,sizeof(TSecureId),EWsGdOpShare);
}
/**
Stops this graphic artwork from being shared with all client sessions with the specific Secure ID.
ShareGlobally() trumps explicit sharing.
@param aClientId the Secure ID of the client sessions to not share with
@return KErrNone if the graphic artwork is no longer shared, KErrNotFound if the graphic was not shared anyway, else one of the system-wide error codes
*/
EXPORT_C TInt CWsGraphic::UnShare(TSecureId aClientId)
{
if(!IsActive())
{
return KErrNotReady;
}
return iPimpl->WriteReply(&aClientId,sizeof(TSecureId),EWsGdOpUnShare);
}
/**
Returns graphic artwork Id.
@return Graphic artwork Id. KNullWsGraphicId if graphic artwork is not active.
*/
EXPORT_C const TWsGraphicId& CWsGraphic::Id() const
{
if(IsActive())
{
return iPimpl->iId;
}
else
{
// fallback
static const TInt KNullWsGraphicId[4] = //binary compatible with TWsGraphicId
{
0, 0, 0, 0
};
__ASSERT_COMPILE(sizeof(KNullWsGraphicId) == sizeof(TWsGraphicId));
return reinterpret_cast<const TWsGraphicId&>(KNullWsGraphicId);
}
}
/**
Checks whether a peer of this graphic artwork has been fully constructed on the server.
@return ETrue if this graphic artwork has a peer CWsGraphic on the server.
*/
EXPORT_C TBool CWsGraphic::IsActive() const
{
return (iPimpl && iPimpl->iWsHandle && (iPimpl->iFlags & CPimpl::EHasPeer));
}
/**
Derived class can override this method to provide custom operations when the client is closed.
*/
EXPORT_C void CWsGraphic::OnClientClose()
{
}
/**
Sends message to this graphic artwork peer on the server.
@param aData User specific data.
*/
EXPORT_C void CWsGraphic::SendMessage(const TDesC8& aData) const
{
TWsClCmdGdSendMessage cmd;
cmd.iDataLen = aData.Size();
__ASSERT_DEBUG(cmd.iDataLen, Panic(EW32PanicGraphicNullData));
cmd.iRemoteReadData = ((aData.Size()+sizeof(cmd))>(TInt)(iPimpl->iBuffer->BufferSize()-sizeof(TWsCmdHeader)));
if(cmd.iRemoteReadData)
{
iPimpl->WriteReplyByProvidingRemoteReadAccess(&cmd,sizeof(cmd),&aData,EWsGdOpSendMsg);
//ignore return value!
}
else
{
iPimpl->Write(&cmd,sizeof(cmd),aData.Ptr(),aData.Size(),EWsGdOpSendMsg);
}
}
EXPORT_C TInt CWsGraphic::SendSynchronMessage(const TDesC8& aData) const
{
TWsClCmdGdSendMessage cmd;
cmd.iDataLen = aData.Size();
__ASSERT_DEBUG(cmd.iDataLen, Panic(EW32PanicGraphicNullData));
cmd.iRemoteReadData = ((aData.Size()+sizeof(cmd))>(TInt)(iPimpl->iBuffer->BufferSize()-sizeof(TWsCmdHeader)));
if(cmd.iRemoteReadData)
{
return iPimpl->WriteReplyByProvidingRemoteReadAccess(&cmd,sizeof(cmd),&aData,EWsGdOpSendSynchronMsg);
}
else
{
return iPimpl->WriteReply(&cmd,sizeof(cmd),aData.Ptr(),aData.Size(),EWsGdOpSendSynchronMsg);
}
}
/**
Flushes window server command buffer
@return One of system-wide error codes.
*/
EXPORT_C TInt CWsGraphic::Flush() const
{
return iPimpl->iBuffer->Flush();
}
EXPORT_C void CWsGraphic::Destroy()
/** Destroys the corresponding CWsGraphicDrawer instance on the server
@released
@publishedAll
*/ {
if(iPimpl && (iPimpl->iFlags & CPimpl::ERegistered))
{
iPimpl->iManager->Remove(this);
}
if(IsActive()) // if iPimpl==NULL, IsActive() returns false
{
__ASSERT_DEBUG(iPimpl != NULL, Panic(EW32PanicGraphicInternal));
iPimpl->Write(EWsGdOpFree);
iPimpl->iWsHandle = 0;
iPimpl->iFlags &= ~CPimpl::EHasPeer;
iPimpl->iManager->ScheduleFlush();
}
}
EXPORT_C void CWsGraphic::SetGraphicExtension(MWsObjectProvider* aExt)
{
iPimpl->iExt = aExt;
}
EXPORT_C RWsSession& CWsGraphic::Session()
{
return *iPimpl->iManager;
}
EXPORT_C TInt CWsGraphic::CWsGraphic_Reserved1()
{
return KErrNotSupported;
}
EXPORT_C TInt CWsGraphic::CWsGraphic_Reserved2()
{
return KErrNotSupported;
}
EXPORT_C TInt CWsGraphic::CWsGraphic_Reserved3()
{
return KErrNotSupported;
}
// TWsGraphicMsgFixedBase \\\\\\\\\\\\\\\\\\\\\\\\
EXPORT_C TWsGraphicMsgFixedBase::TWsGraphicMsgFixedBase(TUid aTypeId,TInt aSizeOfDerived):
/** Protected constructor for subclasses to call
@param aTypeId The UID representing this type of data
@param aSizeOf The size of the derived class
Example:
@code
TMyDerivedFixedMsg::TMyDerivedFixedMsg(): TWsGraphicMsgFixedBase(KUidMyDerivedType,sizeof(TMyDerivedFixedMsg)), ...
@endcode
*/ iTypeId(aTypeId), iSize(aSizeOfDerived-sizeof(TWsGraphicMsgFixedBase))
{
__ASSERT_COMPILE(sizeof(*this) == (sizeof(TInt32)*2));
}
EXPORT_C TPtrC8 TWsGraphicMsgFixedBase::Pckg() const
/** @return this fixed message as a descriptor so that it can be passed as draw data in the CWindowGc::DrawWsGraphic command directly if only one such message is to be sent
*/ {
return TPtrC8(reinterpret_cast<const TUint8*>(this),sizeof(*this) + iSize);
}
EXPORT_C TUid TWsGraphicMsgFixedBase::TypeId() const
/** @return the UID identifying the type of the data that follows */
{
return iTypeId;
}
EXPORT_C TInt TWsGraphicMsgFixedBase::Size() const
/** @return the size of the derived class (not including this fixed base class size) */
{
return iSize;
}
// RWsGraphicMsgBuf \\\\\\\\\\\\\\\\\\\\\\\\
EXPORT_C RWsGraphicMsgBuf::RWsGraphicMsgBuf()
/** Default Constructor */
{
}
TInt RWsGraphicMsgBuf::IntAt(TInt aOfs) const
/** @internalComponent @released */
{
if((aOfs < 0) || ((aOfs+sizeof(TInt)) > Length()))
{
Panic(EW32PanicGraphicBadBuffer);
}
TInt ret;
memcpy(&ret,Ptr()+aOfs,sizeof(TInt));
return ret;
}
EXPORT_C TInt RWsGraphicMsgBuf::Append(TUid aTypeId,const TDesC8& aData)
/** Append a descriptor as data
@param aTypeId the type of the message to append
@param aData arbitrary length data consisting of the whole message
@return KErrNone if successful, else a system-wide error code
*/ {
TInt err = ExpandForAppend(aData.Length());
if (err)
{
return err;
}
WriteHeader(aTypeId,aData.Length());
// append data
Insert(Length(),aData);
return KErrNone;
}
EXPORT_C TInt RWsGraphicMsgBuf::Append(TUid aTypeId,const TDesC16& aData)
/** Append a descriptor as data
@param aTypeId the type of the message to append
@param aData arbitrary length data consisting of the whole message
@return KErrNone if successful, else a system-wide error code
*/ {
TPtr8 data(NULL,0);
TInt err = Append(aTypeId,aData.Size(),data);
if (err)
{
return err;
}
// append data
data.Copy(reinterpret_cast<const TUint8*>(aData.Ptr()),aData.Size());
return KErrNone;
}
TInt RWsGraphicMsgBuf::ExpandForAppend(TInt aDataLen)
/** @internalComponent @released */
{
__ASSERT_COMPILE(sizeof(TInt) == sizeof(TInt32));
const TInt required = (sizeof(TUid) + sizeof(TInt) + aDataLen);
if(MaxLength() < (Length() + required))
{
TInt err = ReAlloc(Length()+required);
if(KErrNone != err)
{
return err;
}
}
return KErrNone;
}
void RWsGraphicMsgBuf::WriteHeader(TUid aTypeId,TInt aLen)
/** @internalComponent @released */
{
__ASSERT_COMPILE(sizeof(TInt) == sizeof(TInt32));
// append header
TPckgBuf<TInt32> i(aTypeId.iUid);
Insert(Length(),i);
i() = aLen;
Insert(Length(),i);
}
EXPORT_C TInt RWsGraphicMsgBuf::Append(TUid aTypeId,TInt aLen,TPtr8& aPtr)
/** Append a message of the specified length and type, and return a pointer to
allow client code to modify the message.
aPtr is only set if the append succeeds.
aPtr is only valid until the next message is appended to the buffer.
@param aTypeId the type of the message to append
@param aLen the length of the message to be reserved
@param aPtr a modifiable descriptor to be used by the client code to write into the message body
@return KErrNone if successful, else a system-wide error code
*/ {
TInt err = ExpandForAppend(aLen);
if (err)
{
return err;
}
WriteHeader(aTypeId,aLen);
// set aPtr
TInt usedLen = Length();
SetLength(usedLen+aLen);
aPtr.Set(MidTPtr(usedLen,aLen));
aPtr.Fill('_'); // prettier when debugging, but want consistant behaviour in release builds
aPtr.Zero();
return KErrNone;
}
EXPORT_C void RWsGraphicMsgBuf::Remove(TInt aIndex)
/** Remove a message from the buffer
@panic if the index is out of bounds
@param aIndex the ordinal position of message to be removed
*/ {
if((aIndex < 0) || (aIndex >= Count()))
{
Panic(EW32PanicGraphicBadBuffer);
}
TPtrC8 ptr = Data(aIndex);
const TInt ofs = (ptr.Ptr()-(sizeof(TInt)*2)-Ptr());
Delete(ofs,ptr.Length() + (sizeof(TInt)*2));
}
EXPORT_C TInt RWsGraphicMsgBuf::Count() const
/** Returns the number of messages in the buffer
@return the number of messages in the buffer
*/ {
const TInt length = Length();
TInt ofs = 0, count = 0;
while(ofs < length)
{
count++;
ofs += IntAt(ofs+sizeof(TInt)) + (sizeof(TInt)*2);
}
if(ofs != length)
{
Panic(EW32PanicGraphicBadBuffer);
}
return count;
}
EXPORT_C TUid RWsGraphicMsgBuf::TypeId(TInt aIndex) const
/** Returns the Type ID of a message in the buffer
@param aIndex the ordinal position of the message
@return the Type ID of the message
@panic if the index is out of bounds
*/ {
const TInt length = Length();
TInt ofs = 0, count = 0;
while(ofs < length)
{
if(count == aIndex)
{
return TUid::Uid(IntAt(ofs));
}
count++;
ofs += IntAt(ofs+sizeof(TInt)) + (sizeof(TInt)*2);
}
Panic(EW32PanicGraphicBadBuffer);
return KNullUid; //dumb compiler
}
EXPORT_C TPtrC8 RWsGraphicMsgBuf::Data(TInt aIndex) const
/** Returns a non-modifiable descriptor of a message body in the buffer
@param aIndex the ordinal position of the message
@return the message body
@panic if the index is out of bounds
*/ {
const TInt length = Length();
TInt ofs = 0, count = 0;
while(ofs < length)
{
if(count == aIndex)
{
return Mid(ofs+(sizeof(TInt)*2),IntAt(ofs+sizeof(TInt)));
}
count++;
ofs += IntAt(ofs+sizeof(TInt)) + (sizeof(TInt)*2);
}
Panic(EW32PanicGraphicBadBuffer);
return TPtrC8(KNullDesC8()); //dumb compiler
}
EXPORT_C TPtr8 RWsGraphicMsgBuf::Data(TInt aIndex)
/** Returns a modifiable descriptor of a message body in the buffer
The returned TPtr8 is only valid until the next message is appended to the buffer.
@param aIndex the ordinal position of the message
@return the message body
@panic if the index is out of bounds
*/ {
const TInt length = Length();
TInt ofs = 0, count = 0;
while(ofs < length)
{
if(count == aIndex)
{
return MidTPtr(ofs+(sizeof(TInt)*2),IntAt(ofs+sizeof(TInt)));
}
count++;
ofs += IntAt(ofs+sizeof(TInt)) + (sizeof(TInt)*2);
}
Panic(EW32PanicGraphicBadBuffer);
return TPtr8(NULL,0); //dumb compiler
}
EXPORT_C const TDesC8& RWsGraphicMsgBuf::Pckg() const
/** Returns the message buffer as a descriptor. Example:
@code
RWsGraphicMsgBuf msgBuf;
msgBuf.Append(...);
...
TWsGraphicId id(...);
SystemGc().DrawWsGraphic(id,Rect(),msgBuf.Pckg());
msgBuf.Close();
@endcode
@see CWindowGc::DrawWsGraphic
@see CCoeControl::Draw
@return the message buffer to be attached a command to draw a CWsGraphic
*/ {
return *this;
}
EXPORT_C TInt RWsGraphicMsgBuf::Append(const TWsGraphicMsgFixedBase& aMsg)
/** Append a fixed-size message
@param aMsg the fixed-size message to append
@return KErrNone if successful, else a system-wide error code
*/ {
__ASSERT_COMPILE(sizeof(TWsGraphicMsgFixedBase) == (sizeof(TInt)*2));
TInt err = ExpandForAppend(aMsg.Size());
if (err)
{
return err;
}
// append data
RBuf8::Append(reinterpret_cast<const TUint8*>(&aMsg),sizeof(TWsGraphicMsgFixedBase) + aMsg.Size());
Count();
return KErrNone;
}
EXPORT_C void RWsGraphicMsgBuf::GetFixedMsg(TWsGraphicMsgFixedBase& aMsg,TInt aIndex) const
/** Returns a copy of a fixed-size message in the buffer
@param a copy of the message
@param aIndex the ordinal position of the message
@panic if the index is out of bounds
@panic the message specified is not of the correct type
*/ {
__ASSERT_COMPILE(sizeof(TWsGraphicMsgFixedBase) == (sizeof(TInt32)*2));
const TInt KHeaderSize = sizeof(TWsGraphicMsgFixedBase);
const TInt length = Length();
TInt ofs = 0, count = 0;
while(ofs < length)
{
if(count == aIndex)
{
if((TUid::Uid(IntAt(ofs)) != aMsg.TypeId()) ||
(IntAt(ofs+sizeof(TInt)) != aMsg.Size()) ||
((ofs + KHeaderSize + aMsg.Size()) > length))
{
Panic(EW32PanicGraphicBadBuffer);
}
memcpy(&aMsg,(Ptr()+ofs),KHeaderSize + aMsg.Size());
return;
}
count++;
ofs += IntAt(ofs+sizeof(TInt)) + (sizeof(TInt)*2);
}
Panic(EW32PanicGraphicBadBuffer);
}