--- /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<TDesC&>(*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<TDesC&>(*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);
+ }
+