mmplugins/mmfwplugins/src/Plugin/subtitle/subtitlegraphicdrawer/mmfsubtitlegraphicdrawer.cpp
author William Roberts <williamr@symbian.org>
Thu, 22 Jul 2010 16:47:59 +0100
branchGCC_SURGE
changeset 36 6320e299b97a
parent 0 40261b775718
permissions -rw-r--r--
Catchup to latest Symbian^4

// Copyright (c) 2008-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:
//

/**
 @file
 @internalComponent
*/

#include <graphics/wsgraphicscontext.h>
#include "mmfsubtitlegraphicdrawer.h"

// Compensation value in microseconds to account for differences in the requested callback time and the actual
// time the callback is delivered
static const TInt KClockDrift=100000;

CMMFSubtitleGraphicDrawer* CMMFSubtitleGraphicDrawer::NewL()
    {
    CMMFSubtitleGraphicDrawer* self = new(ELeave) CMMFSubtitleGraphicDrawer();  
    return self;
    }
    
CMMFSubtitleGraphicDrawer::~CMMFSubtitleGraphicDrawer()
    {
    delete iBitmap1;
    delete iBitmap2;
    delete iTempBitmap;
    }

void CMMFSubtitleGraphicDrawer::ConstructL(MWsGraphicDrawerEnvironment& aEnv, const TGraphicDrawerId& aId, MWsClient& aOwner, const TDesC8& /*aData*/)
    {
    // Note this method is called by the baseclass not CMMFSubtitleGraphicDrawer
    BaseConstructL(aEnv, aId, aOwner);
    
    // Construct bitmap objects.  Do this here as we can leave usefully with
    // any construction errors
	iBitmap1 = new (ELeave) CFbsBitmap();
	iBitmap2 = new (ELeave) CFbsBitmap();
	iTempBitmap = new (ELeave) CFbsBitmap();
    }


// From CwsGraphicDrawer
void CMMFSubtitleGraphicDrawer::HandleMessage(const TDesC8& aData)
    {   
    // Retreive message type from buffer
    TInt8 msgType = aData[0];
    
    switch (msgType)
    	{    	
	case ESubtitleCrpMessageInit:
		{
		iCaptureRegion = ETrue;
		TPckgBuf<TSubtitleCrpMsgInit> message;
		message.Copy(aData);
		ProcessMessageInit(message());
		}
		break;
		
	case ESubtitleCrpMessageInitSimple:
		iCaptureRegion = ETrue;
		iBitmap1Valid=EFalse;
    	iBitmap2Valid=EFalse;
    	iTempBitmapValid=ETrue;
		break;
		
	case ESubtitleCrpMessageDrawFrame:
		{
		iState = ESubtitleGraphicStateDrawFrame;
		TPckgBuf<TSubtitleCrpMsgDrawFrame> message;
		message.Copy(aData);
		ProcessMessageDrawFrame(message());
		}
		break;
		
	case ESubtitleCrpMessageSwapFrame:
		{
		iState = ESubtitleGraphicStateSwapFrame;
		TPckgBuf<TSubtitleCrpMsgRenderSwapFrame> message;
		message.Copy(aData);
        ProcessMessageSwapFrame(message());
		}
        break;
    	
    case ESubtitleCrpMessageClear:
    	iDisplayClearDue.UniversalTime();
    	iState = ESubtitleGraphicStateClear;
    	break;
		
	default:
		// Silently ignore unrecognised messages
		// Clear messages for example require no further processing
		// Set the state to waiting so DoDraw will do nothing.
		iState = ESubtitleGraphicStateWaiting;
	break;
    	}
    
    // Note clear messages require no further processing we just need to invalidate the display

	// Ask WSERV to redraw the CRP
    Invalidate();
    }

void CMMFSubtitleGraphicDrawer::DoDraw(MWsGc& aGc, const TRect& aRect, const TDesC8& /*aData*/) const
	{	
	// For some crp rendering states we need to ensure that this DoDraw has been called
	// in response to Invalidate() and not generated in response to a portion of the CRP
	// becoming invald for some reason (menus, dialogs etc)
	
	// Store the invalid region as our subtitle region to complete initialization.
	if (iCaptureRegion)
		{
		iSubtitleRegion = aRect;
		iCaptureRegion = EFalse;
		}
	
	// If the current state is waiting we do dont need to do anything
	if ((iSubtitleRegion.IsEmpty())||(iState==ESubtitleGraphicStateWaiting))
		{
		return;
		}
	
	switch(iState)
	    {   	
	case ESubtitleGraphicStateDrawFrame:
	case ESubtitleGraphicStateSwapFrame:	
		// Blt new content
		DoBitBlt(aGc, iDirtyRegion);
		
		if ( iDisplayDuration.Int64() > 0 )
			{
			// Schedule a clear frame to remove this subtitle after the requested time
		    // Note clear messages require no further processing we just need to schedule a redraw
			aGc.ScheduleAnimation(iSubtitleRegion, iDisplayDuration.Int64());
			iDisplayClearDue.UniversalTime();
			iDisplayClearDue=iDisplayDuration.Int64()+iDisplayClearDue.Int64()-KClockDrift;
			iState = ESubtitleGraphicStateClear;
			}
		else
			{
			// Redraw this frames content until instructed to stop
			iState = ESubtitleGraphicStateRefreshContent;
			}
	    break;
	
	case ESubtitleGraphicStateRefreshContent:
		// Refresh current frame content
		DoBitBlt(aGc, iDirtyRegion);
		break;
		
	case ESubtitleGraphicStateClear:
		{
		// Clear is due, check to see if the clear is due now
		TTime timeNow;
		timeNow.UniversalTime();
		TInt diff=iDisplayClearDue.Int64()-timeNow.Int64();
		
		if ( diff > 0 )
			{
			// Clear is not due do a standard bitblt		
			DoBitBlt(aGc, iDirtyRegion);
			}
		else
			{
			// No further processing required as WSERV clears the region for us
			iState = ESubtitleGraphicStateWaiting;
			}
		}
		break;
		
	default:
		// Should never happen
#ifdef _DEBUG
		RDebug::Printf("CMMFSubtitleGraphicDrawer::DoDraw() - Invalid State in Drawer should never happen");
		User::Invariant();
#endif
	    break;
	    }
	}

/**
Renders the current bitmap frame
*/
void CMMFSubtitleGraphicDrawer::DoBitBlt(MWsGc& aGc, const TRect& aRect) const
	{
	MWsGraphicsContext* context = aGc.ObjectInterface<MWsGraphicsContext>();
	if(!context)
		{
		RDebug::Printf("CMMFSubtitleGraphicDrawer::DoBitBlt can not get MWsGraphicsContext");
		return;
		}
	context->Push();
	
	switch (iCurrentFrame)
		{
		case ESubtitleGraphicFrame1:
			if (iBitmap1Valid)
				{
				context->BitBlt(iSubtitleRegion.iTl + aRect.iTl, *iBitmap1, aRect);
				}
			break;
		
		case ESubtitleGraphicFrame2:
			if (iBitmap2Valid)
				{
				context->BitBlt(iSubtitleRegion.iTl + aRect.iTl, *iBitmap2, aRect);
				}
			break;
		
		case ESubtitleGraphicFrame3:
			if (iTempBitmapValid)
				{
				context->BitBlt(iSubtitleRegion.iTl + aRect.iTl, *iTempBitmap, aRect);
				}
			break;
		
		default:
			break;
		}

	context->Pop();	
	}

/**
Process initialization message from client.  Readies the CRP for drawing
@param aMessage Message data received from client
*/
void CMMFSubtitleGraphicDrawer::ProcessMessageInit(TSubtitleCrpMsgInit& aMessage)
	{
	// Duplicate client bitmap handles
	// These are verified by the client before they are sent
	iBitmap1->Reset();
	TInt err = iBitmap1->Duplicate(aMessage.iBitmapHandle1);
	
	// This should never be a problem but check in debug modes just in case
	// We dont do this in release mode as it panics the window server...
	__ASSERT_DEBUG(KErrNone==err, User::Invariant());
	
	iBitmap2->Reset();
	err = iBitmap2->Duplicate(aMessage.iBitmapHandle2);
	// This should never be a problem but check in debug modes just in case
	// We dont do this in release mode as it panics the window server...
	__ASSERT_DEBUG(KErrNone==err, User::Invariant());
	
	iCurrentFrame=ESubtitleGraphicFrame1;
	iBitmap1Valid=ETrue;
	iBitmap2Valid=ETrue;
	iTempBitmapValid=EFalse;
	}

/**
Process draw frame message from client.  Draw the bitmap provided.
@param aMessage Message data received from client
*/
void CMMFSubtitleGraphicDrawer::ProcessMessageDrawFrame(TSubtitleCrpMsgDrawFrame& aMessage)
	{
	// Duplicate client bitmap handle
	iTempBitmap->Reset();
	iTempBitmap->Duplicate(aMessage.iBitmapHandle);
	
    iOldDirtyRegion=iDirtyRegion;
	iDirtyRegion=aMessage.iDirtyRegion;
		
    iDisplayDuration=aMessage.iDisplayDuration;
    iCurrentFrame=ESubtitleGraphicFrame3;
	}

/**
Process swap frame message from client.  Draws the current backbuffer provided.
@param aMessage Message data received from client
*/
void CMMFSubtitleGraphicDrawer::ProcessMessageSwapFrame(TSubtitleCrpMsgRenderSwapFrame& aMessage)
	{
	__ASSERT_DEBUG((aMessage.iExpectedFrame==ESubtitleGraphicFrame1)||(aMessage.iExpectedFrame==ESubtitleGraphicFrame2), User::Invariant());
	
	iDisplayDuration = aMessage.iDisplayDuration;
	iOldDirtyRegion=iDirtyRegion;
	iDirtyRegion = aMessage.iDirtyRegion;
	
	// Swap the frame pointer
	iCurrentFrame = static_cast<TSubtitleGraphicFrame>(aMessage.iExpectedFrame);
	}