diff -r 000000000000 -r 5752a19fdefe imaging/imagingfws/src/ImageConversionPriv.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imaging/imagingfws/src/ImageConversionPriv.cpp Wed Aug 25 12:29:52 2010 +0300 @@ -0,0 +1,1745 @@ +// Copyright (c) 2001-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: +// + +#include "ImageClientMain.h" +#include "ImageConversionPriv.h" +#include "icl/ImagePlugin.h" +#include "icl/ImageConstruct.h" +#include "ImageConversion.h" + + + +const TInt KMaxDstBufferSize = 4096; + +/* IMAGE DECODER PRIVATE */ +CImageDecoderPriv::CImageDecoderPriv(CImageDecodeConstruct* aConstruct, MImageDecoderPrivSupport* aSupport) + : CActive(CActive::EPriorityIdle), iImageType(CImageDecoder::EImageTypeMain), iConstruct(aConstruct), iSupport(aSupport), iReadOnly(EFalse), iUseBufferReadOptimization(ETrue) + { + ASSERT(aConstruct != NULL); + ASSERT(aSupport != NULL); + CActiveScheduler::Add(this); + } + +void CImageDecoderPriv::SetFileL(RFs& aFs, const TDesC& aSourceFilename, const CImageDecoder::TOptions aOptions) + { + iFs = &aFs; + iOptions = aOptions; + iImageParameterData.SetFilenamePtr(&aSourceFilename); + delete iContent; + iContent = NULL; + delete iData; + iData = NULL; + iReadOnly=ETrue; + TRAPD(err, iContent = CContent::NewL(*iImageParameterData.SourceFilenamePtr(), EContentShareReadOnly)); + if (err!= KErrNone && err != KErrNoMemory) + { + iReadOnly=EFalse; + iContent = CContent::NewL(*iImageParameterData.SourceFilenamePtr(), EContentShareReadWrite); + } + User::LeaveIfNull(iContent); + iData = iContent->OpenContentL(iIntent, (iUniqueId) ? static_cast(*iUniqueId) : KDefaultContentObject()); + + //Try to find if content is DRM + TInt value = -1; + TInt getAttrResult =iContent->GetAttribute(EIsProtected, value); + if(getAttrResult != KErrNone || value!=0) + { + //either we had an error from getAttribute or EIsProtected is not set to 0 (false) + //Could be DRM content, don't apply iUseBufferReadOptimization + iUseBufferReadOptimization = EFalse; + } + + iCachedDataSize = -1; + } + +void CImageDecoderPriv::SetFileL(RFile& aFile, const CImageDecoder::TOptions aOptions) + { + iOptions = aOptions; + User::LeaveIfError(aFile.Name(iFileName)); + iImageParameterData.SetFilenamePtr(&iFileName); + delete iContent; + iContent = NULL; + delete iData; + iData = NULL; + iContent = CContent::NewL(aFile); + iData = iContent->OpenContentL(iIntent, (iUniqueId) ? static_cast(*iUniqueId) : KDefaultContentObject()); + + //Try to find if content is DRM + TInt value = -1; + TInt getAttrResult =iContent->GetAttribute(EIsProtected, value); + if(getAttrResult != KErrNone || value!=0) + { + //either we had an error from getAttribute or EIsProtected is not set to 0 (false) + //Could be DRM content, don't apply iUseBufferReadOptimization + iUseBufferReadOptimization = EFalse; + } + + iCachedDataSize = -1; + } + +void CImageDecoderPriv::SetDataL(RFs& aFs, const TDesC8& aSourceData, const CImageDecoder::TOptions aOptions) + { + iFs = &aFs; + iOptions = aOptions; + iImageParameterData.SetDataPtr(&aSourceData); + } + +CImageDecoderPriv* CImageDecoderPriv::NewL(CImageDecodeConstruct* aConstruct, MImageDecoderPrivSupport* aSupport) + { + CImageDecoderPriv* self = new (ELeave) CImageDecoderPriv(aConstruct, aSupport); + return self; + } + +CImageDecoderPriv::~CImageDecoderPriv() + { + ASSERT(!IsActive()); + if (iPlugin) + iPlugin->Cleanup(); + iFrameInfo.ResetAndDestroy(); + iFrameData.ResetAndDestroy(); + delete iImageReadCodec; // Created in ScanDataL() + delete iData; + delete iContent; + delete iPlugin; + delete iUniqueId; + } + +void CImageDecoderPriv::Cleanup() + { + delete iReadBuffer; iReadBuffer = NULL; + } + +void CImageDecoderPriv::CreatePluginL() + { + iPlugin = iConstruct->NewPluginL(); + iPlugin->iProperties = this; + } + +/** +@see CImageDecoder::SetImageTypeL +*/ +void CImageDecoderPriv::SetImageTypeL(TInt aImageType) + { + if (aImageType == iImageType) + { + return; + } + + if ( (aImageType == CImageDecoder::EImageTypeThumbnail) && + (iThumbnailData == NULL) ) + { + User::Leave(KErrNotFound); + } + + TInt prevImageType = iImageType; + iImageType = aImageType; + + // Delete the old read codec - a new one will be instantiated by the + // plugin on notification of Image Type change. + delete iImageReadCodec; + iImageReadCodec = NULL; + iCurrentFrame = 0; + iPosition = 0; + TRAPD(err,iPlugin->NotifyImageTypeChangeL(aImageType)); + if(err != KErrNone) + { + delete iImageReadCodec; + iImageReadCodec = NULL; + // Try to switch back to the main image + iImageType = prevImageType; + TRAPD(err2,iPlugin->NotifyImageTypeChangeL(prevImageType)); + if (err2 != KErrNone) + { + // Switching back to the main image type shouldn't fail as corrupt as it has been done once before + // when creating the decoder. + __ASSERT_DEBUG( (err2 != KErrCorrupt), Panic( EInvalidFunctionLeave ) ); + User::Leave(err2); + } + // We report the thumbnail problem to the application + User::Leave(err); + } + } + +void CImageDecoderPriv::SetThumbnailData(HBufC8* aThumbnailData) + { + // The buffer containing the thumbnail data is owned by the plugin + iThumbnailData = aThumbnailData; + } + +/* +Disable optimization of this function by the VC compiler. +This function suffers from the known behaviour of setjmp()/longjmp() +used by the TRAP() harness in that register variables can be 'stomped' +by the longjmp/leave process. +*/ +#ifdef __VC32__ +#pragma optimize("",off) +#endif // __VC32__ +void CImageDecoderPriv::Convert(RThread& aRequestThread, TRequestStatus* aRequestStatus, CFbsBitmap& aDestination, TInt aFrameNumber) + { + if (IsActive()) + Panic(EConvertCalledWhileBusy); + + + iRequestThread = &aRequestThread; + iConvStatus = aRequestStatus; + *iConvStatus = KRequestPending; + + iCurrentFrame = aFrameNumber; + if (iCurrentFrame < 0 || iCurrentFrame >= iFrameInfo.Count()) + { + RequestComplete(KErrArgument); + return; + } + + if (aDestination.Handle() == 0) + Panic(ENoDestinationBitmap); + + if(aDestination.ExtendedBitmapType()!=KNullUid) + { + RequestComplete(KErrNotSupported); + return; + } + + iDestination = &aDestination; + iDestinationHandle = iDestination->Handle(); + iDestinationSize = iDestination->SizeInPixels(); + iDestinationMask = NULL; + TRAPD(error, iPlugin->InitConvertL()); + + if (error!=KErrNone) + RequestComplete(error); + else + SelfComplete(KErrNone); + } +#ifdef __VC32__ +#pragma optimize("",on) +#endif // __VC32__ + +void CImageDecoderPriv::Convert(RThread& aRequestThread, TRequestStatus* aRequestStatus, CFbsBitmap& aDestination, CFbsBitmap& aDestinationMask, TInt aFrameNumber) + { + if (IsActive()) + Panic(EConvertCalledWhileBusy); + + iRequestThread = &aRequestThread; + iConvStatus = aRequestStatus; + *iConvStatus = KRequestPending; + + iCurrentFrame = aFrameNumber; + if (iCurrentFrame < 0 || iCurrentFrame >= iFrameInfo.Count()) + { + RequestComplete(KErrArgument); + return; + } + + if (aDestination.Handle() == 0) + Panic(ENoDestinationBitmap); + + if(aDestination.ExtendedBitmapType()!=KNullUid || (aDestinationMask.Handle()!=0 && aDestinationMask.ExtendedBitmapType()!=KNullUid)) + { + RequestComplete(KErrNotSupported); + return; + } + + iDestination = &aDestination; + iDestinationHandle = iDestination->Handle(); + iDestinationSize = iDestination->SizeInPixels(); + + if (aDestinationMask.Handle() == 0) + Panic(ENoBitmapMask); + else + { + // if we have an alpha channel mask, insist an EGray256 mask bitmap + // else allow either an EGray2 or an EGray256 one + // ie. for compatability allow an EGray256 mask bitmap, even if we only have binary data + TDisplayMode maskDisplayMode = aDestinationMask.DisplayMode(); + const TFrameInfo& frameInfo = FrameInfo(iCurrentFrame); + if (!(maskDisplayMode==EGray256 || + (maskDisplayMode==EGray2 && !(frameInfo.iFlags & TFrameInfo::EAlphaChannel)))) + { + RequestComplete(KErrArgument); + return; + } + // furthermore, if we have a mask, enforce is same size as destination + if (iDestinationSize != aDestinationMask.SizeInPixels()) + { + RequestComplete(KErrArgument); + return; + } + } + + iDestinationMask = &aDestinationMask; + iDestinationMaskHandle = iDestinationMask->Handle(); + + TRAPD(error, iPlugin->InitConvertL()); + + if (error!=KErrNone) + RequestComplete(error); + else + SelfComplete(KErrNone); + } + +void CImageDecoderPriv::ContinueConvert(RThread& aRequestThread, TRequestStatus* aRequestStatus) + { + // NB Not busy and iCurrentProcessingData==true -> we previously stopped on an underflow + // if not true we must have stopped for some other reason and ContinueConvert is illegal + + if (IsActive()) + Panic(EConvertCalledWhileBusy); + + if (!iCurrentlyProcessingData) + Panic(EIllegalContinueConvert); + + ASSERT(iPlugin->ValidDestination()); // if legal we should have an iDestination. Whether iMask depends. + + if (iDestination->Handle() != iDestinationHandle) + Panic(EDifferentDestinationBitmap); + + if (iDestinationMask && (iDestinationMask->Handle() != iDestinationMaskHandle)) + Panic(EDifferentDestinationMask); + + if (iDestination->SizeInPixels() != iDestinationSize) + Panic(EModifiedDestination); + + iRequestThread = &aRequestThread; + iConvStatus = aRequestStatus; + *iConvStatus = KRequestPending; + + SelfComplete(KErrNone); + return; + } + + +TInt CImageDecoderPriv::DataSizeL() + { + TInt dataSize = iCachedDataSize; + if (dataSize == -1) + { + iData->DataSizeL(dataSize); + if(iReadOnly) + iCachedDataSize = dataSize; + } + + return dataSize; + } + +void CImageDecoderPriv::PrepareForProcessFrameL() + { + TInt localSrcLength; + TBool srcHasGrown = EFalse; + + if (iImageParameterData.IsFilename()) + { + ASSERT(iData); + + if(iUseBufferReadOptimization) + { + localSrcLength = DataSizeL(); + } + else + { + iData->DataSizeL(localSrcLength); + } + } + else + { + localSrcLength = iImageParameterData.SourceDataPtr()->Length(); + } + + if (localSrcLength > iSrcLength) + srcHasGrown = ETrue; + + iSrcLength = localSrcLength; + if ((iSrcDes.Length() == 0) || srcHasGrown) + { + // Fetch next buffer. + // Get next block size. + iCurrentBlockLength = iBlockLength; + if ((iCurrentBlockLength + iPosition) > iDataLength) + { + // If current position + read buffer length > Data length then + // iCurrentBlockLength = what ever's left in iDataLength + iCurrentBlockLength = Max(0, iDataLength - iPosition); + } + + // Get the next block of data + TPtrC8 ptr; + ReadDataL((iPosition + iStartPosition), ptr, iCurrentBlockLength); + + // Set iSrcDes to point at next block in the source data. + iSrcDes.Set(ptr); + iCurrentBlockLength = iSrcDes.Length(); + } + + iOldSrcDesLength = iSrcDes.Length(); + } + + + +/** +* Issues a read operation by sending the start position +* along with the destination descriptor and size. +* +* When this function is used to read data from a file, it +* can send the start position and length in one IPC operation, +* and so avoid having to issue a seek first. +* +* Because ContentAccess::CData does not support a synchronous +* version of this API, this function takes care of waiting for +* the operation to complete, and leaves with any error code. +* This simplifies the calling code. +* +* @param aPosition Position in source data to read from. +* @param aDest The data is written into this descriptor. +* @param aSize Amount of data to read in bytes. +* @leave Any Symbian OS error code. +*/ +void CImageDecoderPriv::SeekReadL(TInt aPosition, TDes8& aDest, TInt aSize) + { + #ifdef __WINS__ + RDebug::Printf("sr,%d,%d", aPosition, aSize); + #endif + + TRequestStatus rs; + TInt result=iData->Read(aPosition, aDest, aSize, rs); + User::LeaveIfError(result); + User::WaitForRequest(rs); + User::LeaveIfError(rs.Int()); + } + + +void CImageDecoderPriv::DoConvert() + { + TRAPD(errCode, PrepareForProcessFrameL()); + + if (errCode!=KErrNone) + { + RequestComplete(errCode); + return; + } + + TFrameState codecState = EFrameIncomplete; + if (iCurrentBlockLength) + TRAP(errCode, codecState = iImageReadCodec->ProcessFrameL(iSrcDes)); + + HandleProcessFrameResult(errCode, codecState); + } + +void CImageDecoderPriv::HandleProcessFrameResult(TInt aErrCode, TFrameState aCodecState) + { + if (aErrCode!=KErrNone) + { + ASSERT(aErrCode != KErrUnderflow); + iCurrentlyProcessingData = EFalse; + RequestComplete(aErrCode); + return; + } + + TInt newSrcDesLength = iSrcDes.Length(); + iPosition += iOldSrcDesLength - newSrcDesLength; + + if (aCodecState == EFrameIncompleteRepositionRequest) + { + TInt length = iBlockLength; + TInt position = iPosition + iStartPosition; + iImageReadCodec->GetNewDataPosition(position, length); + if (position<0) + { + iCurrentlyProcessingData = EFalse; + RequestComplete(KErrCorrupt); + return; + } + + iPosition = position-iStartPosition; + } + + if (aCodecState == EBlockComplete) // Block decoded successfully + { + iCurrentlyProcessingData = EFalse; // To avoid call of ContinueConvert() + RequestComplete(KErrNone); + return; + } + + if (aCodecState == EFrameComplete) // Frame decoded successfully + { + iImageReadCodec->Complete(); + iCurrentlyProcessingData = EFalse; + + RequestComplete(KErrNone); + return; + } + else if (newSrcDesLength == iOldSrcDesLength && iCurrentlyProcessingData) // Needs more data than is currently present in the buffer to make progress + { + //call of ContinueConvert() only + //The following method call is required so that codecs can get the data already decoded can be displayed + iImageReadCodec->Complete(); + RequestComplete(KErrUnderflow); + return; + } + + // Each Plug-in has to trigger the active object as it needs RunL called again. + iSrcDes.SetLength(0); + SelfComplete(KErrNone); + } + +TBufPtr8& CImageDecoderPriv::SourceData() + { + return iSrcDes; + } + + +void CImageDecoderPriv::RunL() + { + ASSERT(iStatus==KErrNone); // we don't handle errors at this point. Should only get here on KErrNone + iPlugin->DoConvert(); + } + +void CImageDecoderPriv::RequestComplete(TInt aReason) + { + ASSERT(iPlugin); + iPlugin->NotifyComplete(); + ASSERT(iRequestThread); + + if (iData && aReason == KErrNone && !iIntentHasBeenExecuted) + { + TInt err = iData->ExecuteIntent(iIntent); + if(err == KErrNone) + { + //Intent has been executed. Ensure it is not executed again for this image. + iIntentHasBeenExecuted = ETrue; + } + else + { + aReason = err; + } + } + + if (iConvStatus && (*iConvStatus == KRequestPending) ) + { + iRequestThread->RequestComplete(iConvStatus, aReason); + } + } + +void CImageDecoderPriv::DoCancel() + { + iPlugin->Cleanup(); + + // if SetSelfPending() has been called but not SelfComplete() + // (i.e. the AO is active but there's still an outstanding request) + // then we need to complete the request + if (IsActive() && iStatus == KRequestPending) + SelfComplete(KErrCancel); + + RequestComplete(KErrCancel); + } + +void CImageDecoderPriv::SelfComplete(TInt aReason) + { + if (!IsActive()) // may already be active if SetSelfPending() called + SetActive(); + TRequestStatus* status = &iStatus; + User::RequestComplete(status, aReason); + } + +void CImageDecoderPriv::SetSelfPending() + { + iStatus = KRequestPending; + SetActive(); + } + +void CImageDecoderPriv::ContinueProcessingHeaderL() + { + iCurrentFrame = iFrameInfo.Count(); + iProcessingFrameInfo = EFalse; + + if (iCurrentFrame) + { + TInt previousFrame = iCurrentFrame-1; + iPosition = iFrameInfo[previousFrame]->iCurrentDataOffset; + if (iFrameInfo[previousFrame]->iCurrentFrameState == TFrameInfo::EFrameInfoProcessingFrame) + { + iCurrentFrame--; + iProcessingFrameInfo = ETrue; + } + } + else + iPosition = 0; + + TInt error; + if (iImageReadCodec) + { + TRAP(error,iPlugin->ReadFrameHeadersL()); + } + else + { + TRAP(error,iPlugin->ScanDataL()); + } + + if (error!=KErrNone && error!=KErrUnderflow) // ignore underflow at this point + User::Leave(error); + } + +void CImageDecoderPriv::CreateFrameInfoL() + { + // Create a new instance of TFrameInfo and initialise it. + // Insert it into the frame info array and store the frame offset. + // Mark the frame as being processed. + TFrameInfo* newFrameInfo = new(ELeave) TFrameInfo(iImageInfo); + + CleanupStack::PushL(newFrameInfo); // push in case insert fails + User::LeaveIfError(iFrameInfo.Insert(newFrameInfo, iCurrentFrame)); + CleanupStack::Pop(); // newFrameInfo + + iFrameInfo[iCurrentFrame]->iFrameDataOffset = iNextFrameOffset; + iProcessingFrameInfo = EFalse; + + CFrameImageData* newFrameData = CFrameImageData::NewL(iImageData); + CleanupStack::PushL(newFrameData); + + User::LeaveIfError(iFrameData.Insert(newFrameData, iCurrentFrame)); + CleanupStack::Pop(); // newFrameData + + iImageReadCodec->SetCurrentFrame(iCurrentFrame); + iImageReadCodec->InitFrameHeader(*iFrameInfo[iCurrentFrame], *iFrameData[iCurrentFrame]); + } + +void CImageDecoderPriv::DeleteFrameInfoL() + { + // If process data needs another block but we don't have one because + // this block is incomplete. + if (iFrameInfo.Count()>1) + { + // Delete the new frame as it is incomplete. + iSupport->Lock(); + delete iFrameInfo[iCurrentFrame]; + iFrameInfo.Remove(iCurrentFrame); + + delete iFrameData[iCurrentFrame]; + iFrameData.Remove(iCurrentFrame); + + iHaveCompleteImageHeaders = EFalse; + iSupport->Unlock(); + iSupport->SaveFrameCount(FrameCount()); + return; + } + else //may need to do some more clean-up + { + // No headers at all, so just leave. + iSupport->Lock(); + iFrameInfo.ResetAndDestroy(); + iFrameData.ResetAndDestroy(); + iSupport->Unlock(); + iSupport->SaveFrameCount(FrameCount()); + User::Leave(KErrUnderflow); + } + } + +void CImageDecoderPriv::ReadFrameHeadersL() + { + ASSERT(iImageReadCodec); // further down, assumes we can call ProcessHeaderL on the codec + + TFrameState codecState; + TFrameInfo::TFrameInfoState frameState; + + iNextFrameOffset = iPosition; + iCurrentlyProcessingData = EFalse; + iBlockLength = iPlugin->FrameHeaderBlockSize(iCurrentFrame); + + do + { + iSrcLength = iBlockLength; + if ((iSrcLength + iPosition) > iDataLength) + { + // If current position + read buffer length > Data length then + // srcLength = what ever's left in iDataLength + iSrcLength = Max(0, iDataLength - iPosition); + } + + TPtrC8 ptr; + ReadDataL((iPosition + iStartPosition), ptr, iSrcLength); + iSrcDes.Set(ptr); + iSrcLength = iSrcDes.Length(); + + TInt err; + if (!iProcessingFrameInfo) + { + iSupport->Lock(); + + //Do not leave between lock and unlock + TRAP(err, CreateFrameInfoL()); + + iSupport->Unlock(); + if (err != KErrNone) + { // In case of leave, we need to reset the pointer arrays + iSupport->Lock(); + iFrameInfo.ResetAndDestroy(); + iFrameData.ResetAndDestroy(); + iSupport->Unlock(); + iSupport->SaveFrameCount(FrameCount()); + User::Leave(err); + } + + iSupport->SaveFrameCount(FrameCount()); + } + + // Process Header for one frame. + codecState = EFrameIncomplete; + err = KErrUnderflow; + if (iSrcLength) + TRAP(err, codecState = iImageReadCodec->ProcessFrameHeaderL(iSrcDes)); + + if ((err != KErrNone) && (err != KErrUnderflow)) + User::Leave(err); + + TInt newSrcLength = iSrcDes.Length(); + frameState = iFrameInfo[iCurrentFrame]->iCurrentFrameState; + if ((err == KErrUnderflow) || ((codecState == EFrameIncomplete) && (iSrcLength == newSrcLength))) + { + if ((frameState == TFrameInfo::EFrameInfoUninitialised) || (frameState == TFrameInfo::EFrameInfoProcessingFrameHeader)) + DeleteFrameInfoL(); + return; + } + + if (codecState == EFrameIncompleteRepositionRequest) + { + TInt length = iBlockLength; + TInt position = iPosition+iStartPosition; + iImageReadCodec->GetNewDataPosition(position, length); + if (position<0) + User::Leave(KErrCorrupt); + + iPosition = position-iStartPosition; + } + else + iPosition += iSrcLength - newSrcLength; + + iNextFrameOffset = iPosition; // Store next frame header offset. + iProcessingFrameInfo = (frameState == TFrameInfo::EFrameInfoProcessingFrameHeader) || (frameState == TFrameInfo::EFrameInfoProcessingFrame); + if ((frameState == TFrameInfo::EFrameInfoProcessingFrame) || (frameState == TFrameInfo::EFrameInfoProcessingComplete)) + { + iFrameInfo[iCurrentFrame]->iCurrentDataOffset = iPosition; + + if (frameState == TFrameInfo::EFrameInfoProcessingComplete) + iCurrentFrame++; + } + } + while ((codecState == EFrameIncomplete) || (codecState == EFrameIncompleteRepositionRequest)); + + // Frame header read complete + if(frameState == TFrameInfo::EFrameInfoProcessingFrameHeader) + DeleteFrameInfoL(); + + iHaveCompleteImageHeaders = ETrue; + } + +void CImageDecoderPriv::InitConvertL() + { + ASSERT((iCurrentFrame >= 0) && (iCurrentFrame < iFrameInfo.Count())); + + // Set position to start of frame. + iPosition = iFrameInfo[iCurrentFrame]->iFrameDataOffset; + + // Re-set conversion variables. + iSrcLength = 0; + + // Set flag to say that we are now converting an image. + iCurrentlyProcessingData = ETrue; + + // Re-initialise block length and codec + iBlockLength = iPlugin->FrameBlockSize(iCurrentFrame); + + TBool disableErrorDiffusion = (iOptions & CImageDecoder::EOptionNoDither); + iImageReadCodec->SetCurrentFrame(iCurrentFrame); + iImageReadCodec->InitFrameL(*iFrameInfo[iCurrentFrame], *iFrameData[iCurrentFrame], disableErrorDiffusion, *iDestination, iDestinationMask); + + } + +void CImageDecoderPriv::RequestInitL(TInt aFrameNumber) + { + __ASSERT_ALWAYS(!IsActive(), Panic(EConvertCalledWhileBusy)); + __ASSERT_ALWAYS((aFrameNumber >= 0) && (aFrameNumber < iFrameInfo.Count()), User::Leave(KErrArgument)); + + // Set current frame. + iCurrentFrame = aFrameNumber; + iImageReadCodec->SetCurrentFrame(iCurrentFrame); + + // Set position to start of frame. + iPosition = iFrameInfo[iCurrentFrame]->iFrameDataOffset; + + // Re-set conversion variables. + iSrcLength = 0; + + // Set flag to say that we are now converting an image. + iCurrentlyProcessingData = ETrue; + + // Re-initialise block length and codec + iBlockLength = iPlugin->FrameBlockSize(iCurrentFrame); + } + +const TFrameInfo& CImageDecoderPriv::FrameInfo(TInt aFrameNumber) const + { + // Return the frame info for a particular frame + __ASSERT_ALWAYS((aFrameNumber >= 0) && (aFrameNumber < iFrameInfo.Count()), Panic(EFrameNumberOutOfRange)); + return *iFrameInfo[aFrameNumber]; + } + +CFrameInfoStrings* CImageDecoderPriv::FrameInfoStringsLC(TInt aFrameNumber) + { + CFrameInfoStrings* frameInfoStrings; + if (iFs == NULL) + { + RFs localRFs; + CleanupClosePushL(localRFs); + + User::LeaveIfError(localRFs.Connect()); + frameInfoStrings = iPlugin->FrameInfoStringsL(localRFs, aFrameNumber); + CleanupStack::PopAndDestroy(); // localRFs + } + else + frameInfoStrings = iPlugin->FrameInfoStringsL(*iFs, aFrameNumber); + + CleanupStack::PushL(frameInfoStrings); + return frameInfoStrings; + } + +void CImageDecoderPriv::ReadDataL(TInt aPosition, TPtrC8& aReadBuffer, TInt aLength) + { + ASSERT(aPosition >= 0); + ASSERT(aLength >= 0); + + TBool srcIsFile = ETrue; + TInt srcSize = 0; + TInt size = aLength; + + if (iImageType == CImageDecoder::EImageTypeThumbnail) + { + ASSERT(iThumbnailData!=NULL); + + srcSize = iThumbnailData->Length(); + + // if trying to start reading past end of file do nothing + if(aPosition >= srcSize) + { + aReadBuffer.Set(KNullDesC8); + return; + } + + if((aPosition + size) > srcSize) + { + // there is not enough data left read what is left. + size = srcSize - aPosition; + } + + const TDesC8* srcDes = iThumbnailData; + ASSERT(srcDes != NULL); + aReadBuffer.Set(srcDes->Mid(aPosition, size)); + iSrcDes.Set(aReadBuffer); + } + else + { + + if(iImageParameterData.IsFilename()) + { // The source if a file + ASSERT(iData); // The file has to be open + if (iUseBufferReadOptimization) + { + srcSize = DataSizeL(); + } + else + { + iData->DataSizeL(srcSize); + } + + + srcIsFile = ETrue; + } + else + { // The source is a descriptor + srcSize = iImageParameterData.SourceDataPtr()->Length(); + srcIsFile = EFalse; + } + + // if trying to start reading past end of file do nothing + if(aPosition >= srcSize) + { + aReadBuffer.Set(KNullDesC8); + return; + } + + if((aPosition + size) > srcSize) + { + // there is not enough data left read what is left. + size = srcSize - aPosition; + } + + TBool bufferedRead = srcIsFile || MustUseBufferWithDescriptor(); + + if(bufferedRead) + { + TBool allocNewBuf = EFalse; + + // read source into local buffer + if(iReadBuffer == NULL) + { + iReadBuffer = HBufC8::NewMaxL(size); + allocNewBuf = ETrue; + } + + TPtr8 ptr(iReadBuffer->Des()); + //Grow iReadBuffer if necessary + if(ptr.MaxLength() < size) + { + delete iReadBuffer; iReadBuffer = NULL; + iReadBuffer = HBufC8::NewMaxL(size); + ptr.Set(iReadBuffer->Des()); + allocNewBuf = ETrue; + } + + if (srcIsFile) + { + if (iUseBufferReadOptimization) + { + // See if the end of the last read overlaps the start of the next read. + TInt extent = aPosition + size; + TBool overlaps = + // not newly-created buffer + ! allocNewBuf + // start position at or before start of last read + && iLastPos <= aPosition + // extent (end position) currently in buffer + && iLastExtent > aPosition && iLastExtent <= extent; + + if (overlaps) + { + // copy the overlap portion to the start of the read buffer + TInt overlapOffset = aPosition - iLastPos; + TInt overlapAmount = iLastExtent - aPosition; + ptr.Copy(ptr.Mid(overlapOffset, overlapAmount)); + + // read the excess from the file + // expand ptr, else MidTPtr will only use the current data + // after the overlap amount for its maximum length + ptr.SetMax(); + TPtr8 excess(ptr.MidTPtr(overlapAmount)); + SeekReadL(aPosition + overlapAmount, excess, size - overlapAmount); + + ptr.SetLength(overlapAmount + excess.Length()); + } + + else + { + SeekReadL(aPosition, ptr, size); + } + + iLastPos = aPosition; + iLastExtent = extent; + } + else + { + User::LeaveIfError(iData->Seek(ESeekStart, aPosition)); + User::LeaveIfError(iData->Read(ptr, size)); + } + + } + else + { + ASSERT(!srcIsFile && MustUseBufferWithDescriptor()); + const TDesC8* srcDes = iImageParameterData.SourceDataPtr(); + ASSERT(srcDes != NULL); + CopyBufferToDescriptor(ptr, *srcDes, aPosition, size); + } + aReadBuffer.Set(iReadBuffer->Des()); + } + else + {//Read block from descriptor + const TDesC8* srcDes = iImageParameterData.SourceDataPtr(); + ASSERT(srcDes != NULL); + aReadBuffer.Set(srcDes->Mid(aPosition, size)); + } + iSrcDes.Set(aReadBuffer); + } + } + +void CImageDecoderPriv::HandleNewlyOpenedImageL() + { + // Tell the plugin that the user wants mask generation. + if (iOptions & CImageDecoder::EAllowGeneratedMask) + iPlugin->EnableMaskGeneration(); + + // call ScanDataL to read in the first header, at least. + TRAPD(error,iPlugin->ScanDataL()); + + // ignore underflow at this point only if the user has set the EOptionAllowZeroFrameOpen flag + if (error == KErrUnderflow) + if (iOptions & CImageDecoder::EOptionAllowZeroFrameOpen) + return; + else + User::Leave(error); + + + if (error!=KErrNone) + User::Leave(error); + } + +TUid CImageDecoderPriv::ImplementationUid() const + { + return iConstruct->ImplementationUid(); + } + +/** + * Passes on CustomSyncL to plugin + * + */ + +void CImageDecoderPriv::CustomSyncL(TInt aParam) + { + iPlugin->HandleCustomSyncL(aParam); + } + +/** + * Plugin is interrogated with InitCustomAsyncL. If this works, then set internal Convert() cycle going + * + */ + +void CImageDecoderPriv::CustomAsync(RThread& aRequestThread, TRequestStatus* aRequestStatus, TInt aParam) + { + __ASSERT_ALWAYS(!IsActive(), Panic(EConvertCalledWhileBusy)); + + TRAPD(error, iPlugin->InitCustomAsyncL(aParam)); + + iRequestThread = &aRequestThread; + iConvStatus = aRequestStatus; + *iConvStatus = KRequestPending; + + if (error==KErrNone) + SelfComplete(KErrNone); + else + RequestComplete(error); + } + +/** + * Indicate if running in a separate thread + * + */ + +TBool CImageDecoderPriv::AmInThread() const + { + return iSupport->AmInThread(); + } + +/** + * Indicate if a decode should abort early (ie. following a Cancel). Always false unless in a thread. + * + */ + +TBool CImageDecoderPriv::ShouldAbort() const + { + return iSupport->ShouldAbort(); + } + +void CImageDecoderPriv::SetIntent(ContentAccess::TIntent aIntent) + { + iIntent = aIntent; + } + +void CImageDecoderPriv::SetUniqueIdL(const TDesC& aUniqueId) + { + delete iUniqueId; + iUniqueId = NULL; + iUniqueId = aUniqueId.AllocL(); + } + +TInt CImageDecoderPriv::SetAgentProperty(ContentAccess::TAgentProperty aProperty, TInt aValue) + { + return iContent->SetProperty(aProperty, aValue); + } + +TInt CImageDecoderPriv::ReductionFactor(const TSize& aOriginalSize, const TSize& aReducedSize) const + { + return iImageReadCodec->ReductionFactor(aOriginalSize, aReducedSize); + } + +TInt CImageDecoderPriv::ReducedSize(const TSize& aOriginalSize, TInt aReductionFactor, TSize& aReducedSize) const + { + return iImageReadCodec->ReducedSize(aOriginalSize, aReductionFactor, aReducedSize); + } + +void CImageDecoderPriv::GetExtensionL(TUid aExtUid, MImageConvExtension*& aExtPtr) + { + iPlugin->GetExtensionL(aExtUid, aExtPtr); + } + +void CImageDecoderPriv::SetClippingRectL(const TRect* aClipRect) + { + iPlugin->SetClippingRectL(aClipRect); + } + +TInt CImageDecoderPriv::GetDestinationSize(TSize& aSize, TInt aFrameNumber) + { + return iPlugin->GetDestinationSize(aSize, aFrameNumber); + } + +void CImageDecoderPriv::RegisterClientRequestStatus(RThread& aRequestThread, TRequestStatus* aRequestStatus) + { + __ASSERT_ALWAYS(!IsActive(), Panic(EFwExtensionBusy)); + + iRequestThread = &aRequestThread; + iConvStatus = aRequestStatus; + *iConvStatus = KRequestPending; + } + +void CImageDecoderPriv::StartActivity() + { + SetSelfPending(); + SelfComplete(KErrNone); + } + +/* IMAGE ENCODER PRIVATE*/ +CImageEncoderPriv* CImageEncoderPriv::NewL(CImageEncodeConstruct* aConstruct, MImageEncoderPrivSupport* aSupport) + { + CImageEncoderPriv* self = new (ELeave) CImageEncoderPriv(aConstruct, aSupport); + return self; + } + +void CImageEncoderPriv::SetFileL(RFs& aFs, const TDesC& aDestinationFilename, const CImageEncoder::TOptions aOptions) + { + iFs = &aFs; + User::LeaveIfError(iFile.Replace(*iFs, aDestinationFilename, EFileWrite | EFileShareAny)); + iImageParameterData.SetFilenamePtr(&aDestinationFilename); + iOptions = aOptions; + +#if defined(SYMBIAN_ENABLE_ENCODER_ASYNC_WRITES) + ASSERT( iAsyncFileWriter == NULL ); + iAsyncFileWriter = CAsyncFileWriter::NewL(*this,iFile, KMaxDstBufferSize ); + iAsyncFileWriter->CheckBufferOut( iDstDes ); +#endif // defined(SYMBIAN_ENABLE_ENCODER_ASYNC_WRITES) + } + +void CImageEncoderPriv::SetFileL(RFile& aFile, const CImageEncoder::TOptions aOptions) + { + User::LeaveIfError(iFile.Duplicate(aFile)); + TInt pos = 0; + User::LeaveIfError(iFile.Seek(ESeekStart, pos)); + User::LeaveIfError(iFile.Name(iFileName)); + iImageParameterData.SetFilenamePtr(&iFileName); + iOptions = aOptions; + +#if defined(SYMBIAN_ENABLE_ENCODER_ASYNC_WRITES) + ASSERT( iAsyncFileWriter == NULL ); + iAsyncFileWriter = CAsyncFileWriter::NewL(*this, iFile, KMaxDstBufferSize ); + iAsyncFileWriter->CheckBufferOut( iDstDes ); +#endif // defined(SYMBIAN_ENABLE_ENCODER_ASYNC_WRITES) + } + + +void CImageEncoderPriv::SetThumbnail(TBool aDoGenerateThumbnail) + { + iPlugin->SetThumbnail(aDoGenerateThumbnail); + } + +void CImageEncoderPriv::SetDataL(HBufC8*& aDestinationData, const CImageEncoder::TOptions aOptions) + { + iDestination = &aDestinationData; + iImageParameterData.SetDataPtr(aDestinationData); + iOptions = aOptions; + } + +CImageEncoderPriv::CImageEncoderPriv(CImageEncodeConstruct* aConstruct, MImageEncoderPrivSupport* aSupport) + : CActive(CActive::EPriorityIdle), iConstruct(aConstruct), iSupport(aSupport) + { + ASSERT(aConstruct); + CActiveScheduler::Add(this); + } + +CImageEncoderPriv::~CImageEncoderPriv() + { + ASSERT(!IsActive()); + if (iPlugin) + iPlugin->Cleanup(); + iFile.Close(); + delete iFinalDstBuffer; + delete iPlugin; +#if defined(SYMBIAN_ENABLE_ENCODER_ASYNC_WRITES) + delete iAsyncFileWriter; +#endif // defined(SYMBIAN_ENABLE_ENCODER_ASYNC_WRITES) + } + +void CImageEncoderPriv::CreatePluginL() + { + iPlugin = iConstruct->NewPluginL(); + iPlugin->iProperties = this; + } + +TInt CImageEncoderPriv::CurrentImageSizeL() const + { + TInt size; + if( iImageParameterData.IsFilename()) + { + ASSERT(iFile.SubSessionHandle() != 0); + User::LeaveIfError(iFile.Size(size)); + } + else + { + ASSERT(iFinalDstBuffer != NULL); + size = iFinalDstBuffer->Length(); + } + return size; + } + +void CImageEncoderPriv::Cleanup() + { + if(iImageParameterData.IsDataTypeDefined()) + { + if (iImageParameterData.IsFilename() && (iFile.SubSessionHandle() != 0)) + { + if(iFs != NULL) + { + // Delete file + TFileName fileName; + iFile.FullName(fileName); + iFile.Close(); + iFs->Delete(fileName); + } + else + { + // Set file length zero + iFile.SetSize(0); + iFile.Close(); + } + } + } + + // Delete any objects we should get rid of + delete iImageWriteCodec; iImageWriteCodec = NULL; // Created in Convert() + delete iDstBuffer; iDstBuffer = NULL; // Created in Convert() + +#if defined(SYMBIAN_ENABLE_ENCODER_ASYNC_WRITES) + delete iAsyncFileWriter; iAsyncFileWriter = NULL; +#endif // defined(SYMBIAN_ENABLE_ENCODER_ASYNC_WRITES) + } + +void CImageEncoderPriv::InitConvertL() + { + ASSERT(iSource != NULL); + iImageWriteCodec->InitFrameL(iDstDes, *iSource); + } + +void CImageEncoderPriv::RequestInitL() + { + __ASSERT_ALWAYS(!IsActive(), Panic(EConvertCalledWhileBusy)); + __ASSERT_ALWAYS(!iConvertStarted, Panic(EIllegalEncoderRestart)); + + // once encoding starts, the encoder must not be reused + iConvertStarted = ETrue; + +#if defined(SYMBIAN_ENABLE_ENCODER_ASYNC_WRITES) + if(!iImageParameterData.IsFilename()) +#endif + { + if (!iDstBuffer) + { + iDstBuffer = HBufC8::NewMaxL(KMaxDstBufferSize); + } + iDstDes.Set(iDstBuffer->Des()); + } + + iHeaderWritten=EFalse; + } + +void CImageEncoderPriv::Convert(RThread& aRequestThread, TRequestStatus* aRequestStatus, const CFbsBitmap& aSource, const CFrameImageData* aFrameImageData) + { + if (iConvertStarted) + Panic(EIllegalEncoderRestart); + + if (IsActive()) + Panic(EConvertCalledWhileBusy); + + // once encoding starts, the encoder must not be reused + iConvertStarted = ETrue; + + iRequestThread = &aRequestThread; + iConvStatus = aRequestStatus; + *iConvStatus = KRequestPending; + iSource = &aSource; + + iFrameInfo.iOverallSizeInPixels = iSource->SizeInPixels(); + iFrameInfo.iFrameSizeInTwips = iSource->SizeInTwips(); + + if(aSource.Handle()!=0 && aSource.ExtendedBitmapType()!=KNullUid) + { + RequestComplete(KErrNotSupported); + return; + } + + TRAPD(leaveErr, iPlugin->PrepareEncoderL(aFrameImageData)); + if (leaveErr != KErrNone) + { + RequestComplete(leaveErr); + return; + } + +#if defined(SYMBIAN_ENABLE_ENCODER_ASYNC_WRITES) + if (! iImageParameterData.IsFilename() ) +#endif + { + + if (!iDstBuffer) + { + TRAP(leaveErr, iDstBuffer = HBufC8::NewMaxL(KMaxDstBufferSize)); + if (leaveErr != KErrNone) + { + RequestComplete(leaveErr); + return; + } + } + + iDstDes.Set(iDstBuffer->Des()); + } + + TRAP(leaveErr, iPlugin->InitConvertL()); + if(leaveErr != KErrNone) + { + RequestComplete(leaveErr); + return; + } + + // we generate the exif data and write it + // this method is asynchronous: it also starts generating the thumbnail + TRequestStatus* status=&iStatus; + SetSelfPending(); + TRAP(leaveErr, iPlugin->WriteExifDataL(status)); + if(leaveErr != KErrNone) + { + RequestComplete(leaveErr); + return; + } + iHeaderWritten=EFalse; + + // the wating for the request to complete is initiated in the Image plugin + } + +void CImageEncoderPriv::RunL() + { + if(!iHeaderWritten) + { + if(iStatus.Int()!=KErrNone) + { + RequestComplete( iStatus.Int() ); + } + else + { + // the thumbnail image has been created, we can now write it in the file + TRAPD(leaveErr, iPlugin->WriteThumbnailL()); + if(leaveErr != KErrNone) + { + RequestComplete(leaveErr); + return; + } + + // Write the JFIF header + TRAP(leaveErr,WriteDataPositionIncL(iStartPosition,iDstDes)); + if (leaveErr != KErrNone) + { + RequestComplete(leaveErr); + return; + } + + iHeaderWritten=ETrue; + SelfComplete(KErrNone); + } + } + else + { + iPlugin->DoConvert(); + } + } + +void CImageEncoderPriv::DoCancel() + { + iPlugin->Cleanup(); + + // if SetSelfPending() has been called but not SelfComplete() + // (i.e. the AO is active but there's still an outstanding request) + // then we need to complete the request + if (IsActive() && iStatus == KRequestPending) + SelfComplete(KErrCancel); + + RequestComplete(KErrCancel); + } + +void CImageEncoderPriv::RequestComplete(TInt aReason) + { + ASSERT(iPlugin); + iPlugin->NotifyComplete(); + ASSERT(iRequestThread); + if (iConvStatus && (*iConvStatus == KRequestPending) ) + { + iRequestThread->RequestComplete(iConvStatus, aReason); + } + } + +void CImageEncoderPriv::WriteDataL(TInt aPosition,const TDesC8& aDes) + { + ASSERT(aPosition >= 0); + ASSERT(aDes.Length() >= 0); + + TInt destSize = 0; + + if(iImageParameterData.IsFilename()) + { // The source if a file + ASSERT(iFile.SubSessionHandle() != 0); // The file has to be open + User::LeaveIfError(iFile.Size(destSize)); + + //If we start writing past EOF + if (aPosition > destSize) + { + User::LeaveIfError(iFile.SetSize(aPosition)); + } + User::LeaveIfError(iFile.Write(aPosition,aDes)); + // if the data has been appended to the file, we need to update the current position in the text + } + else + { // The source is a descriptor + const TInt totalSize = aPosition + aDes.Length(); + // totalSize is equal to the minimum length that the + // destination descriptor has to be. It is NOT the total + // length of the destination descriptor - NJ + + if (iFinalDstBuffer == NULL) + { + iFinalDstBuffer = HBufC8::NewMaxL(totalSize); + } + destSize = iFinalDstBuffer->Length(); + + //The buffer is too small + if (destSize < totalSize) + { + iFinalDstBuffer = iFinalDstBuffer->ReAllocL(totalSize); + } + + // check to see if we are extending the descriptor (eg. append) + if (totalSize > destSize) + { + iFinalDstBuffer->Des().SetLength(totalSize); + } + + // replace the current descriptor contents with the new data + iFinalDstBuffer->Des().Replace(aPosition,aDes.Length(),aDes); + } + } + +void CImageEncoderPriv::WriteDataPositionIncL(TInt aPosition,const TDesC8& aDes) + { + WriteDataL(aPosition, aDes); + if(aPosition+aDes.Length() > iPosition) + { + iPosition+=aDes.Length(); + } + } + +void CImageEncoderPriv::SelfComplete(TInt aReason) + { + if (!IsActive()) // may already be active if SetSelfPending() called + SetActive(); + TRequestStatus* status = &iStatus; + User::RequestComplete(status, aReason); + } + +void CImageEncoderPriv::SetSelfPending() + { + iStatus = KRequestPending; + SetActive(); + } + +void CImageEncoderPriv::DoConvert() + { + TFrameState codecState = EFrameIncomplete; + TRAPD(errCode, codecState = iImageWriteCodec->ProcessFrameL(iDstDes)); + + HandleProcessFrameResult(errCode, codecState); + } + +#if defined(SYMBIAN_ENABLE_ENCODER_ASYNC_WRITES) + +/*virtual*/ +void CImageEncoderPriv::BufferWritten(const TPtrC8& aWritten, TInt aErrorCode) + { + if (aErrorCode == KErrNone) + { + iAsyncFileWriter->CheckBufferIn(aWritten); + } + + if (aErrorCode != KErrNone) + { + iWriterError = aErrorCode; + RequestComplete( iWriterError ); + return; + } + } + +void CImageEncoderPriv::HandleProcessFrameResult(TInt aErrCode, TFrameState aCodecState) + { + if (aErrCode == KErrNone) + { + TRAP(aErrCode, DoHandleProcessFrameResultL(aCodecState) ); + } + + if (aErrCode != KErrNone) + { + RequestComplete(aErrCode); + } + } + +void CImageEncoderPriv::DoHandleProcessFrameResultL(TFrameState aCodecState) + { + User::LeaveIfError( iWriterError ); + + const TBool lastBuffer = (aCodecState == EFrameComplete || (aCodecState != EBlockComplete && iDstDes.Length() == 0)); + + if(iImageParameterData.IsFilename()) + { // The source if a file + ASSERT(iFile.SubSessionHandle() != 0); // The file has to be open + + if (lastBuffer) + { + User::LeaveIfError( iAsyncFileWriter->FlushBuffers() ); + } + + TPtr8 newBuffer(NULL, 0); + iAsyncFileWriter->WriteBufferL(iDstDes, iStartPosition + iPosition); + + iAsyncFileWriter->CheckBufferOut( newBuffer ); + + if(iStartPosition + iPosition + iDstDes.Length() > iPosition) + { + iPosition+=iDstDes.Length(); + } + iDstDes.Set( newBuffer ); + } + else + { + WriteDataPositionIncL(iStartPosition + iPosition, iDstDes); + } + + if (lastBuffer || aCodecState == EBlockComplete) + { + if(lastBuffer) + { + FinishConvertL(); + } + RequestComplete(KErrNone); + } + else + { + SelfComplete(KErrNone); + } + } + +#else + +void CImageEncoderPriv::HandleProcessFrameResult(TInt aErrCode, TFrameState aCodecState) + { + if (aErrCode != KErrNone) + { + RequestComplete(aErrCode); + return; + } + + if (aCodecState == EFrameComplete || iDstDes.Length() == 0) + iLastBuffer = ETrue; + + TRAPD(leaveErr,WriteDataPositionIncL(iStartPosition + iPosition, iDstDes)); + if (leaveErr != KErrNone) + { + RequestComplete(leaveErr); + return; + } + + if (iLastBuffer || aCodecState == EBlockComplete) + { + if(iLastBuffer) + { + TRAP(leaveErr, FinishConvertL()); + } + iLastBuffer = EFalse; + RequestComplete(leaveErr); + } + else + { + SelfComplete(KErrNone); + } + } +#endif // defined(SYMBIAN_ENABLE_ENCODER_ASYNC_WRITES) + +TBufPtr8& CImageEncoderPriv::DestinationData() + { + return iDstDes; + } + +void CImageEncoderPriv::FinishConvertL() + { + iPlugin->UpdateHeaderL(); + if (!iImageParameterData.IsFilename()) + { + *iDestination = iFinalDstBuffer; + iFinalDstBuffer = NULL; + } + else + { + iFile.Close(); // close the file + } + } + +TUid CImageEncoderPriv::ImplementationUid() const + { + return iConstruct->ImplementationUid(); + } + +const CFrameImageData& CImageDecoderPriv::FrameData(TInt aFrameNumber) const + { + // Return the frame image data for a particular frame. + __ASSERT_ALWAYS((aFrameNumber >= 0) && (aFrameNumber < iFrameInfo.Count()), Panic(EFrameNumberOutOfRange)); + return *iFrameData[aFrameNumber]; + } + + +/** + * Passes on CustomSyncL to plugin + * + */ + +void CImageEncoderPriv::CustomSyncL(TInt aParam) + { +#if ( defined(WRITER_EMULATE_SLOW_MEDIA) && defined(SYMBIAN_ENABLE_ENCODER_ASYNC_WRITES) ) +// that's for testing/debugging only ! + if ( aParam == KUidIclTestEmulateSlowMedia.iUid && iAsyncFileWriter != NULL ) + { + iAsyncFileWriter->iEmulateSlowMedia = ETrue; + return; + } +#endif + + iPlugin->HandleCustomSyncL(aParam); + } + +/** + * Plugin is interrogated with InitCustomAsyncL. If this works, then set internal Convert() cycle going + * + */ + +void CImageEncoderPriv::CustomAsync(RThread& aRequestThread, TRequestStatus* aRequestStatus, TInt aParam) + { + __ASSERT_ALWAYS(!IsActive(), Panic(EConvertCalledWhileBusy)); + + TRAPD(error, iPlugin->InitCustomAsyncL(aParam)); + + iRequestThread = &aRequestThread; + iConvStatus = aRequestStatus; + *iConvStatus = KRequestPending; + + if (error==KErrNone) + SelfComplete(KErrNone); + else + RequestComplete(error); + } + +/** + * Indicate if running in a separate thread + * + */ + +TBool CImageEncoderPriv::AmInThread() const + { + return iSupport->AmInThread(); + } + +/** + * Indicate if a decode should abort early (ie. following a Cancel). Always false unless in a thread. + * + */ + +TBool CImageEncoderPriv::ShouldAbort() const + { + return iSupport->ShouldAbort(); + } + +void CImageEncoderPriv::GetExtensionL(TUid aExtUid, MImageConvExtension*& aExtPtr) + { + iPlugin->GetExtensionL(aExtUid, aExtPtr); + } + +void CImageEncoderPriv::RegisterClientRequestStatus(RThread& aRequestThread, TRequestStatus* aRequestStatus) + { + __ASSERT_ALWAYS(!IsActive(), Panic(EConvertCalledWhileBusy)); + + iRequestThread = &aRequestThread; + iConvStatus = aRequestStatus; + *iConvStatus = KRequestPending; + } + +void CImageEncoderPriv::StartActivity() + { + SetSelfPending(); + SelfComplete(KErrNone); + } + +// CImageDataArray +CImageDataArray::~CImageDataArray() + { + iImageData.ResetAndDestroy(); + iImageBuffers.ResetAndDestroy(); + } + +// Inline these. +TInt CImageDataArray::InsertImageData(const TImageDataBlock* aEntry, TInt aPos) + { + ASSERT(aEntry != NULL); + return iImageData.Insert(aEntry, aPos); + } + +TInt CImageDataArray::AppendImageData(const TImageDataBlock* aEntry) + { + ASSERT(aEntry != NULL); + return iImageData.Append(aEntry); + } + +void CImageDataArray::RemoveImageData(TInt aIndex) + { + iImageData.Remove(aIndex); + } + +// Get image data/local image data. +const TImageDataBlock* CImageDataArray::GetImageData(TInt aIndex) const + { + return iImageData[aIndex]; + } + +TImageDataBlock* CImageDataArray::GetImageData(TInt aIndex) + { + return iImageData[aIndex]; + } + +// Get num entries. +TInt CImageDataArray::ImageDataCount() const + { + return iImageData.Count(); + } + +// Append image buffer. +TInt CImageDataArray::AppendImageBuffer(const HBufC8* aImageBuffer) + { + return iImageBuffers.Append(aImageBuffer); + } +