sl@0: // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: @internalComponent sl@0: */ sl@0: sl@0: #include sl@0: #include "mmfsubtitlegraphicdrawer.h" sl@0: sl@0: // Compensation value in microseconds to account for differences in the requested callback time and the actual sl@0: // time the callback is delivered sl@0: static const TInt KClockDrift=100000; sl@0: sl@0: CMMFSubtitleGraphicDrawer* CMMFSubtitleGraphicDrawer::NewL() sl@0: { sl@0: CMMFSubtitleGraphicDrawer* self = new(ELeave) CMMFSubtitleGraphicDrawer(); sl@0: return self; sl@0: } sl@0: sl@0: CMMFSubtitleGraphicDrawer::~CMMFSubtitleGraphicDrawer() sl@0: { sl@0: delete iBitmap1; sl@0: delete iBitmap2; sl@0: delete iTempBitmap; sl@0: } sl@0: sl@0: void CMMFSubtitleGraphicDrawer::ConstructL(MWsGraphicDrawerEnvironment& aEnv, const TGraphicDrawerId& aId, MWsClient& aOwner, const TDesC8& /*aData*/) sl@0: { sl@0: // Note this method is called by the baseclass not CMMFSubtitleGraphicDrawer sl@0: BaseConstructL(aEnv, aId, aOwner); sl@0: sl@0: // Construct bitmap objects. Do this here as we can leave usefully with sl@0: // any construction errors sl@0: iBitmap1 = new (ELeave) CFbsBitmap(); sl@0: iBitmap2 = new (ELeave) CFbsBitmap(); sl@0: iTempBitmap = new (ELeave) CFbsBitmap(); sl@0: } sl@0: sl@0: sl@0: // From CwsGraphicDrawer sl@0: void CMMFSubtitleGraphicDrawer::HandleMessage(const TDesC8& aData) sl@0: { sl@0: // Retreive message type from buffer sl@0: TInt8 msgType = aData[0]; sl@0: sl@0: switch (msgType) sl@0: { sl@0: case ESubtitleCrpMessageInit: sl@0: { sl@0: iCaptureRegion = ETrue; sl@0: TPckgBuf message; sl@0: message.Copy(aData); sl@0: ProcessMessageInit(message()); sl@0: } sl@0: break; sl@0: sl@0: case ESubtitleCrpMessageInitSimple: sl@0: iCaptureRegion = ETrue; sl@0: iBitmap1Valid=EFalse; sl@0: iBitmap2Valid=EFalse; sl@0: iTempBitmapValid=ETrue; sl@0: break; sl@0: sl@0: case ESubtitleCrpMessageDrawFrame: sl@0: { sl@0: iState = ESubtitleGraphicStateDrawFrame; sl@0: TPckgBuf message; sl@0: message.Copy(aData); sl@0: ProcessMessageDrawFrame(message()); sl@0: } sl@0: break; sl@0: sl@0: case ESubtitleCrpMessageSwapFrame: sl@0: { sl@0: iState = ESubtitleGraphicStateSwapFrame; sl@0: TPckgBuf message; sl@0: message.Copy(aData); sl@0: ProcessMessageSwapFrame(message()); sl@0: } sl@0: break; sl@0: sl@0: case ESubtitleCrpMessageClear: sl@0: iDisplayClearDue.UniversalTime(); sl@0: iState = ESubtitleGraphicStateClear; sl@0: break; sl@0: sl@0: default: sl@0: // Silently ignore unrecognised messages sl@0: // Clear messages for example require no further processing sl@0: // Set the state to waiting so DoDraw will do nothing. sl@0: iState = ESubtitleGraphicStateWaiting; sl@0: break; sl@0: } sl@0: sl@0: // Note clear messages require no further processing we just need to invalidate the display sl@0: sl@0: // Ask WSERV to redraw the CRP sl@0: Invalidate(); sl@0: } sl@0: sl@0: void CMMFSubtitleGraphicDrawer::DoDraw(MWsGc& aGc, const TRect& aRect, const TDesC8& /*aData*/) const sl@0: { sl@0: // For some crp rendering states we need to ensure that this DoDraw has been called sl@0: // in response to Invalidate() and not generated in response to a portion of the CRP sl@0: // becoming invald for some reason (menus, dialogs etc) sl@0: sl@0: // Store the invalid region as our subtitle region to complete initialization. sl@0: if (iCaptureRegion) sl@0: { sl@0: iSubtitleRegion = aRect; sl@0: iCaptureRegion = EFalse; sl@0: } sl@0: sl@0: // If the current state is waiting we do dont need to do anything sl@0: if ((iSubtitleRegion.IsEmpty())||(iState==ESubtitleGraphicStateWaiting)) sl@0: { sl@0: return; sl@0: } sl@0: sl@0: switch(iState) sl@0: { sl@0: case ESubtitleGraphicStateDrawFrame: sl@0: case ESubtitleGraphicStateSwapFrame: sl@0: // Blt new content sl@0: DoBitBlt(aGc, iDirtyRegion); sl@0: sl@0: if ( iDisplayDuration.Int64() > 0 ) sl@0: { sl@0: // Schedule a clear frame to remove this subtitle after the requested time sl@0: // Note clear messages require no further processing we just need to schedule a redraw sl@0: aGc.ScheduleAnimation(iSubtitleRegion, iDisplayDuration.Int64()); sl@0: iDisplayClearDue.UniversalTime(); sl@0: iDisplayClearDue=iDisplayDuration.Int64()+iDisplayClearDue.Int64()-KClockDrift; sl@0: iState = ESubtitleGraphicStateClear; sl@0: } sl@0: else sl@0: { sl@0: // Redraw this frames content until instructed to stop sl@0: iState = ESubtitleGraphicStateRefreshContent; sl@0: } sl@0: break; sl@0: sl@0: case ESubtitleGraphicStateRefreshContent: sl@0: // Refresh current frame content sl@0: DoBitBlt(aGc, iDirtyRegion); sl@0: break; sl@0: sl@0: case ESubtitleGraphicStateClear: sl@0: { sl@0: // Clear is due, check to see if the clear is due now sl@0: TTime timeNow; sl@0: timeNow.UniversalTime(); sl@0: TInt diff=iDisplayClearDue.Int64()-timeNow.Int64(); sl@0: sl@0: if ( diff > 0 ) sl@0: { sl@0: // Clear is not due do a standard bitblt sl@0: DoBitBlt(aGc, iDirtyRegion); sl@0: } sl@0: else sl@0: { sl@0: // No further processing required as WSERV clears the region for us sl@0: iState = ESubtitleGraphicStateWaiting; sl@0: } sl@0: } sl@0: break; sl@0: sl@0: default: sl@0: // Should never happen sl@0: #ifdef _DEBUG sl@0: RDebug::Printf("CMMFSubtitleGraphicDrawer::DoDraw() - Invalid State in Drawer should never happen"); sl@0: User::Invariant(); sl@0: #endif sl@0: break; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Renders the current bitmap frame sl@0: */ sl@0: void CMMFSubtitleGraphicDrawer::DoBitBlt(MWsGc& aGc, const TRect& aRect) const sl@0: { sl@0: MWsGraphicsContext* context = aGc.ObjectInterface(); sl@0: if(!context) sl@0: { sl@0: RDebug::Printf("CMMFSubtitleGraphicDrawer::DoBitBlt can not get MWsGraphicsContext"); sl@0: return; sl@0: } sl@0: context->Push(); sl@0: sl@0: switch (iCurrentFrame) sl@0: { sl@0: case ESubtitleGraphicFrame1: sl@0: if (iBitmap1Valid) sl@0: { sl@0: context->BitBlt(iSubtitleRegion.iTl + aRect.iTl, *iBitmap1, aRect); sl@0: } sl@0: break; sl@0: sl@0: case ESubtitleGraphicFrame2: sl@0: if (iBitmap2Valid) sl@0: { sl@0: context->BitBlt(iSubtitleRegion.iTl + aRect.iTl, *iBitmap2, aRect); sl@0: } sl@0: break; sl@0: sl@0: case ESubtitleGraphicFrame3: sl@0: if (iTempBitmapValid) sl@0: { sl@0: context->BitBlt(iSubtitleRegion.iTl + aRect.iTl, *iTempBitmap, aRect); sl@0: } sl@0: break; sl@0: sl@0: default: sl@0: break; sl@0: } sl@0: sl@0: context->Pop(); sl@0: } sl@0: sl@0: /** sl@0: Process initialization message from client. Readies the CRP for drawing sl@0: @param aMessage Message data received from client sl@0: */ sl@0: void CMMFSubtitleGraphicDrawer::ProcessMessageInit(TSubtitleCrpMsgInit& aMessage) sl@0: { sl@0: // Duplicate client bitmap handles sl@0: // These are verified by the client before they are sent sl@0: iBitmap1->Reset(); sl@0: TInt err = iBitmap1->Duplicate(aMessage.iBitmapHandle1); sl@0: sl@0: // This should never be a problem but check in debug modes just in case sl@0: // We dont do this in release mode as it panics the window server... sl@0: __ASSERT_DEBUG(KErrNone==err, User::Invariant()); sl@0: sl@0: iBitmap2->Reset(); sl@0: err = iBitmap2->Duplicate(aMessage.iBitmapHandle2); sl@0: // This should never be a problem but check in debug modes just in case sl@0: // We dont do this in release mode as it panics the window server... sl@0: __ASSERT_DEBUG(KErrNone==err, User::Invariant()); sl@0: sl@0: iCurrentFrame=ESubtitleGraphicFrame1; sl@0: iBitmap1Valid=ETrue; sl@0: iBitmap2Valid=ETrue; sl@0: iTempBitmapValid=EFalse; sl@0: } sl@0: sl@0: /** sl@0: Process draw frame message from client. Draw the bitmap provided. sl@0: @param aMessage Message data received from client sl@0: */ sl@0: void CMMFSubtitleGraphicDrawer::ProcessMessageDrawFrame(TSubtitleCrpMsgDrawFrame& aMessage) sl@0: { sl@0: // Duplicate client bitmap handle sl@0: iTempBitmap->Reset(); sl@0: iTempBitmap->Duplicate(aMessage.iBitmapHandle); sl@0: sl@0: iOldDirtyRegion=iDirtyRegion; sl@0: iDirtyRegion=aMessage.iDirtyRegion; sl@0: sl@0: iDisplayDuration=aMessage.iDisplayDuration; sl@0: iCurrentFrame=ESubtitleGraphicFrame3; sl@0: } sl@0: sl@0: /** sl@0: Process swap frame message from client. Draws the current backbuffer provided. sl@0: @param aMessage Message data received from client sl@0: */ sl@0: void CMMFSubtitleGraphicDrawer::ProcessMessageSwapFrame(TSubtitleCrpMsgRenderSwapFrame& aMessage) sl@0: { sl@0: __ASSERT_DEBUG((aMessage.iExpectedFrame==ESubtitleGraphicFrame1)||(aMessage.iExpectedFrame==ESubtitleGraphicFrame2), User::Invariant()); sl@0: sl@0: iDisplayDuration = aMessage.iDisplayDuration; sl@0: iOldDirtyRegion=iDirtyRegion; sl@0: iDirtyRegion = aMessage.iDirtyRegion; sl@0: sl@0: // Swap the frame pointer sl@0: iCurrentFrame = static_cast(aMessage.iExpectedFrame); sl@0: }