diff -r 000000000000 -r 5752a19fdefe imaging/imagingfws/src/Test/TImageViewer/TImageViewer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imaging/imagingfws/src/Test/TImageViewer/TImageViewer.cpp Wed Aug 25 12:29:52 2010 +0300 @@ -0,0 +1,2946 @@ +// Copyright (c) 1997-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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include +#include +#endif +#include "TImageViewer.h" + +const TInt KVideoMinZoomFactor = -3; +const TInt KVideoMaxZoomFactor = 0; + +const TInt KDefaultStreamDelay = 1000000; // 1s. Used when streaming non-animated +const TInt KDefaultFolderDelay = 2000000; // 2s. Used when playing a folder + +const TInt KButtonMoveIncr = 16; +const TInt KScaleFactor = 10; + +const TInt KInfoBufferSize = 1024; + +_LIT(KDefPath, "C:\\"); +const TInt KShortestPossiblePath=4; + +// #define __USE_PURE_SCALING // fine scaling scales to 1/2, 1/4 and 1/8 - check non-universal scaling + +#define __CLEAR_BITMAPS_FIRST // for debugging purposes, get TImageViewer to clear bitmaps prior to + // decode conversion. Really the codecs should do this, but... + +inline TBool IsMngImage(const CImageDecoder* aDecoder) + { + TUid type, subtype; + aDecoder->ImageType(0, type, subtype); + return (type.iUid==KMngMimeTypeUidValue); + } + +inline TBool HasMoreMngFrames(const CImageDecoder* aDecoder) + { + const TFrameInfo& info=aDecoder->FrameInfo(0); + return (info.iFlags & TFrameInfo::EMngMoreFramesToDecode); + } + +CPluginInfoArray* CPluginInfoArray::NewL() + { + CPluginInfoArray* self = new (ELeave) CPluginInfoArray; + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +void CPluginInfoArray::ConstructL() + { + RefreshPluginListL(); + } + +CPluginInfoArray::CPluginInfoArray() + { + } + +void CPluginInfoArray::Reset() + { + iPluginArray.ResetAndDestroy(); + } + +void CPluginInfoArray::RefreshPluginListL() + { + Reset(); + CImageEncoder::GetImageTypesL(iPluginArray); + } + +CPluginInfoArray::~CPluginInfoArray() + { + Reset(); + } + +TInt CPluginInfoArray::MdcaCount() const + { + return iPluginArray.Count(); + } + +TPtrC CPluginInfoArray::MdcaPoint(TInt aIndex) const + { + return iPluginArray[aIndex]->Description(); + } + +TUid CPluginInfoArray::ImageType(TInt aIndex) + { + return iPluginArray[aIndex]->ImageType(); + } + +TUid CPluginInfoArray::SubType(TInt aIndex) + { + return iPluginArray[aIndex]->SubType(); + } + +// CFrameInfoDialog +class CFrameInfoDialog : public CEikDialog + { +public: + CFrameInfoDialog(const TDesC& aPropertiesText, const TDesC& aImageCommentText, const TDesC& aFrameCommentText); + +protected: + void PreLayoutDynInitL(); + +private: + const TDesC& iPropertiesText; + const TDesC& iImageCommentText; + const TDesC& iFrameCommentText; + }; + +CFrameInfoDialog::CFrameInfoDialog(const TDesC& aPropertiesText, const TDesC& aImageCommentText, const TDesC& aFrameCommentText) + : iPropertiesText(aPropertiesText), iImageCommentText(aImageCommentText), iFrameCommentText(aFrameCommentText) + { + } + +void CFrameInfoDialog::PreLayoutDynInitL() + { + // Grab each Edwin and set the text. + CEikEdwin* page = STATIC_CAST(CEikEdwin*, Control(EFramePropertiesPage)); + page->SetTextL(&iPropertiesText); + + page = STATIC_CAST(CEikEdwin*, Control(EImageCommentsPage)); + page->SetTextL(&iImageCommentText); + + page = STATIC_CAST(CEikEdwin*, Control(EFrameCommentsPage)); + page->SetTextL(&iFrameCommentText); + } + +// +// CVideoWalker +// + +class CVideoWalker : public CActive + { +public: + static CVideoWalker* NewL(CVideoAppUi* aAppUi); + ~CVideoWalker(); + TRequestStatus& ActiveStatus(); + void SelfComplete(TInt aError); +protected: + CVideoWalker(CVideoAppUi* aAppUi); + // from CActive + void RunL(); + void DoCancel(); +protected: + CVideoAppUi* const iAppUi; // not owned + }; + + +// +// CVideoAppUi +// + +CVideoAppUi::CVideoAppUi(): + iStreamBuffer(NULL,0,0) + { + iDecoderOptions = (CImageDecoder::EAllowGeneratedMask | CImageDecoder::EPreferFastDecode); + } + +void CVideoAppUi::ConstructL() + { + CEikAppUi::ConstructL(); + + iAppView = CVideoAppView::NewL(ClientRect()); + + ::new(&iFrame) CWsBitmap(iEikonEnv->WsSession()); + ::new(&iMask) CWsBitmap(iEikonEnv->WsSession()); + + iRotator = CBitmapRotator::NewL(); + iScaler = CBitmapScaler::NewL(); + + iBackgroundColor = KRgbWhite.Color16(); + + iAppView->SetBackgroundColor(TRgb::Color16(iBackgroundColor), ENoDrawNow); + + iWalker = CVideoWalker::NewL(this); + User::LeaveIfError(iTimer.CreateLocal()); + iStreamGen = CVideoWalker::NewL(this); + User::LeaveIfError(iStreamTimer.CreateLocal()); + + // Note iStreamSeed deliberated left as 0 to give consistent behaviour + + iSaveInfo.iImageTypeUid = KImageTypeJPGUid; + iSaveInfo.iBpp = 6; + iSaveInfo.iColor = ETrue; + iSaveInfo.iQualityFactor = 40; + iSaveInfo.iSampling = 2; + + iUseNativeDisplayMode = ETrue; + + iScalingCoefficient = 1; // Full size + } + +CVideoAppUi::~CVideoAppUi() + { + Cancel(); + + iFrame.Reset(); + iMask.Reset(); + if (iAppView) + { + RemoveFromStack(iAppView); + delete iAppView; + } + delete iFrameImageData; + delete iLoadUtil; + delete iSaveUtil; + delete iRotator; + delete iScaler; + delete iWalker; + iTimer.Close(); + iStreamTimer.Close(); + delete iStreamGen; + User::Free(REINTERPRET_CAST(TAny*,CONST_CAST(TUint8*, iStreamBuffer.Ptr()))); + delete iDir; + iOperations.Close(); + } + +void CVideoAppUi::Cancel() + { + if (iWalker) + iWalker->Cancel(); // if active will callback on DoCancel() + if (iStreamGen) + iStreamGen->Cancel(); + iState = EIdle; + } + +TKeyResponse CVideoAppUi::HandleKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType) + { + TKeyResponse ret = EKeyWasConsumed; + + if (aType!=EEventKey) + return ret; + + TUint code = aKeyEvent.iCode; + + switch (code) + { + case EKeyLeftArrow: + case EKeyRightArrow: + case EKeyUpArrow: + case EKeyDownArrow: + { + if ( aKeyEvent.iModifiers & EModifierShift ) + { + // update crop region + UpdateClippingRect(code); + } + else + { + TPoint moveBy; + switch (code) + { + case EKeyLeftArrow: + moveBy.SetXY(KButtonMoveIncr,0); + break; + case EKeyRightArrow: + moveBy.SetXY(-KButtonMoveIncr,0); + break; + case EKeyUpArrow: + moveBy.SetXY(0,KButtonMoveIncr); + break; + case EKeyDownArrow: + moveBy.SetXY(0,-KButtonMoveIncr); + break; + } + iAppView->MoveBy(moveBy); + } + } + break; + case EKeyEscape: + Cancel(); + ASSERT(iState==EIdle); + iEikonEnv->BusyMsgCancel(); + iEikonEnv->InfoMsg(_L("Cancelled")); + break; + default: + ret = EKeyWasNotConsumed; + break; + } + return ret; + } + +void CVideoAppUi::HandleCommandL(TInt aCommand) + { + switch (aCommand) + { + case EVideoCmdOpenFile: + OpenFileL(EFileTypeUnknown); + break; + case EVideoCmdOpenOtaFile: + OpenFileL(EFileTypeOta); + break; + case EVideoCmdOpenWbmpFile: + OpenFileL(EFileTypeWbmp); + break; + case EVideoCmdOpenFolder: + OpenFolderL(); + break; + case EVideoCmdSaveAs: + SaveAsL(); + break; + case EVideoCmdMask: + iDisableMask = ! iDisableMask; + if (iDisableMask) + { + iEikonEnv->InfoMsg(_L("Mask reset")); + } + else + { + iEikonEnv->InfoMsg(_L("Mask enabled")); + } + if (iMask.Handle() && iDisableMask) + { + iMask.Reset(); + } + else if (iMask.Handle()==0 && !iDisableMask) + { + User::LeaveIfError(iMask.Create(TSize(0,0),EGray256)); + } + break; + case EVideoCmdZoomIn: + iZoomFactor++; + if (iZoomFactor > KVideoMaxZoomFactor) + iZoomFactor = KVideoMinZoomFactor; + if ( iUseExtensions ) + { + iScalingCoefficient = iZoomFactor - 1; + } + LoadFileL(); + break; + case EVideoCmdZoomOut: + iZoomFactor--; + if (iZoomFactor < KVideoMinZoomFactor) + iZoomFactor = KVideoMaxZoomFactor; + if ( iUseExtensions ) + { + iScalingCoefficient = iZoomFactor - 1; + } + LoadFileL(); + break; + case EVideoCmdFineZoomIn: + ZoomFrameL(ETrue); + break; + case EVideoCmdFineZoomOut: + ZoomFrameL(EFalse); + break; + case EVideoCmdDisplayMode: + DisplayModeL(); + break; + case EVideoCmdBackgroundColor: + BackgroundColorL(); + break; + case EVideoCmdPlay: + if (iState == EPlaying || iState == ELoading) + iEikonEnv->InfoMsg(_L("Busy...")); + else + PlayClipL(); + break; + case EVideoCmdStream: + StreamPlayL(EFileTypeUnknown); + break; + case EVideoCmdOtaStream: + StreamPlayL(EFileTypeOta); + break; + case EVideoCmdWbmpStream: + StreamPlayL(EFileTypeWbmp); + break; + case EVideoCmdDecoderOptions: + DecoderOptionsL(); + break; + case EVideoCmdExtension: + ExtensionOptionsL(); + break; + case EVideoCmdUseExtensions: + iUseExtensions = !iUseExtensions; + break; + case EVideoCmdRefresh: + LoadFileL(); + break; + case EVideoCmdExtractFrame: + ExtractFrameL(); + break; + case EVideoCmdExtractStreamedFrame: + StreamPlayL(EFileTypeUnknown, ETrue); + break; + case EVideoCmdFrameInfo: + FrameInfoL(); + break; + case EVideoCmdRotateClockwise: + FrameRotateL(ETrue); + break; + case EVideoCmdRotateAntiClockwise: + FrameRotateL(EFalse); + break; + case EVideoCmdMirrorHorizontalAxis: + FrameMirrorL(ETrue); + break; + case EVideoCmdMirrorVerticalAxis: + FrameMirrorL(EFalse); + break; + case EEikCmdExit: + Exit(); + break; + default: + iEikonEnv->InfoMsg(R_VIDEO_UNKNOWN); + break; + } + } + +TBool CVideoAppUi::ProcessCommandParametersL(TApaCommand aCommand,TFileName& aDocumentName,const TDesC8& aTail) + { + switch (aCommand) + { + case EApaCommandOpen: + iLoadFileName = aDocumentName; + break; + case EApaCommandCreate: + case EApaCommandRun: + break; + case EApaCommandBackground: + default: + break; + } + + return CEikAppUi::ProcessCommandParametersL(aCommand,aDocumentName,aTail); + } + +void CVideoAppUi::OpenFileL(TFileType aFileType) + { + if (iLoadFileName.Length() < KShortestPossiblePath) + iLoadFileName = KDefPath; + + Cancel(); + delete iLoadUtil; iLoadUtil = NULL; + + TInt title; + switch (aFileType) + { + default: + title = 0; + break; + case EFileTypeWbmp: + title = R_VIDEO_OPEN_WBMP; + break; + case EFileTypeOta: + title = R_VIDEO_OPEN_OTA; + break; + } + CEikDialog* dialog = new(ELeave) CEikFileOpenDialog(&iLoadFileName, title); + if (!dialog->ExecuteLD(R_EIK_DIALOG_FILE_OPEN)) + return; + + iLastFileType = aFileType; + iOpeningFolder = EFalse; + LoadFileL(); + } + +void CVideoAppUi::OpenFolderL() + { + Cancel(); + + if (iLoadFileName.Length() < KShortestPossiblePath) + iLoadFileName = KDefPath; + + TFileName folderName = iLoadFileName; + + CEikDialog* dialog = new(ELeave) CEikFileOpenDialog(&folderName, R_VIDEO_SELECT_FOLDER); + if (!dialog->ExecuteLD(R_EIK_DIALOG_FILE_OPEN)) + return; + + iLastFileType = EFileTypeUnknown; + iOpeningFolder = ETrue; + LoadFolderL(folderName); + } + +void CVideoAppUi::DecoderOptionsL() + { + CEikDialog* dialog = new(ELeave) CDecoderOptionsDialog(iDecoderOptions); + dialog->ExecuteLD(R_VIDEO_DECODER_OPTIONS_DIALOG); + } + +void CVideoAppUi::ExtensionOptionsL() + { + CEikDialog* dialog = new(ELeave) CExtensionOptionsDialog(iClippingRect, + iOperations, + iScalingCoefficient, + iScalingQuality, + iLockAspectRatio); + TInt buttonPressed = dialog->ExecuteLD(R_VIDEO_DECODER_EXTENSION_DIALOG); + if ( buttonPressed == EEikBidOk && iLoadUtil ) + { + // re-convert the image e.g. if clipping rect has changed + LoadFileL(); + } + } + +void CVideoAppUi::LoadFileL() + { + Cancel(); + if ( !iLoadUtil ) + { + if (iLoadFileName.Length() < KShortestPossiblePath) + return; + + TUid format; + switch (iLastFileType) + { + case EFileTypeOta: + format = KImageTypeOTAUid; + break; + case EFileTypeWbmp: + format = KImageTypeWBMPUid; + break; + default: + format = KNullUid; + } + + TRAPD(error,iLoadUtil = CImageDecoder::FileNewL(iCoeEnv->FsSession(), iLoadFileName, CImageDecoder::TOptions(iDecoderOptions), format)); + if (error!=KErrNone) + { + iEikonEnv->HandleError(error); + iAppView->Reset(EDrawNow); // ensure we redraw whole screen - replace previous cross if required + return; + } + } + + HandleNewlyOpenedImageL(); + + StartFrameOpen(EPlaying); + } + +void CVideoAppUi::LoadFolderL(const TDesC& aDirName) + { + delete iDir; iDir = NULL; + + TParsePtrC parse(aDirName); + iDirName = parse.DriveAndPath(); + + iEikonEnv->FsSession().GetDir(iDirName, 0, 0, iDir); + + if (iDir->Count()==0) + { + iEikonEnv->InfoMsg(R_VIDEO_EMPTY_FOLDER); + return; + } + + iDirIndex = 0; + OpenNextFolderEntry(); + } + +void CVideoAppUi::OpenNextFolderEntry() + { + if (iDirIndex >= iDir->Count()) + { + // end of processing - so stop + iEikonEnv->BusyMsgCancel(); + Cancel(); + iState = EIdle; + return; + } + + const TEntry& entry = (*iDir)[iDirIndex]; + iLoadFileName.Copy(iDirName); + iLoadFileName.Append(entry.iName); + + delete iLoadUtil; + iLoadUtil = NULL; + TRAPD(error, LoadFileL()); + + if (error==KErrNone) + iEikonEnv->InfoMsg(entry.iName); + else + { + TBuf<64> errorMsg; + errorMsg.Format(_L("%S - error %d"), &entry.iName, error); + iEikonEnv->InfoMsg(errorMsg); + LoadFolderWait(); + } + } + +void CVideoAppUi::DynInitMenuPaneL(TInt aResourceId,CEikMenuPane* aMenuPane) + { + if(aResourceId==R_VIDEO_CLIP_MENU) + { + if (iLoadUtil==NULL || iState!=EIdle) // nothing open or we are busy + aMenuPane->SetItemDimmed(EVideoCmdPlay,ETrue); + } + else if (aResourceId==R_VIDEO_OPERATE_MENU) + { + if (iLoadUtil==NULL || iState!=EIdle || iUseExtensions) + { + // nothing open or we are busy + aMenuPane->SetItemDimmed(EVideoCmdRotateClockwise,ETrue); + aMenuPane->SetItemDimmed(EVideoCmdRotateAntiClockwise,ETrue); + aMenuPane->SetItemDimmed(EVideoCmdMirrorHorizontalAxis,ETrue); + aMenuPane->SetItemDimmed(EVideoCmdMirrorVerticalAxis,ETrue); + } + } + else if (aResourceId==R_VIDEO_ZOOM_MENU) + { + if (iLoadUtil==NULL || iState!=EIdle || iUseExtensions) + { + aMenuPane->SetItemDimmed(EVideoCmdZoomIn,ETrue); + aMenuPane->SetItemDimmed(EVideoCmdZoomOut,ETrue); + } + } + else if ( aResourceId==R_VIDEO_VIEW_MENU ) + { + aMenuPane->SetItemButtonState(EVideoCmdUseExtensions,(iUseExtensions) ? EEikMenuItemSymbolOn : 0); + } + } + +TBool CVideoAppUi::CheckHotKeyNotDimmedL(TInt aCommandId) + { + TInt result = ETrue; + switch (aCommandId) + { + case EVideoCmdPlay: + case EVideoCmdRotateClockwise: + case EVideoCmdRotateAntiClockwise: + case EVideoCmdFineZoomIn: + case EVideoCmdFineZoomOut: + case EVideoCmdMirrorHorizontalAxis: + case EVideoCmdMirrorVerticalAxis: + if (iLoadUtil==NULL || iState!=EIdle || iUseExtensions) + result = EFalse; + break; + default: + // do nothing + break; + } + return result; + } + +void CVideoAppUi::LoadFolderWait() + { + ASSERT(!iWalker->IsActive()); // if we get here, should not be doing anything + + iTimer.After(iWalker->ActiveStatus(), KDefaultFolderDelay); + iState = EFolderWait; + } + +void CVideoAppUi::HandleNewlyOpenedImageL() + { + ASSERT(iLoadUtil); // should have already been opened + + TFrameInfo frameInfo = iLoadUtil->FrameInfo(0); + + // jf 3/12/01. Assume frame 0 gives the main image characteristics + iOverallSize = frameInfo.iOverallSizeInPixels; + if (iOverallSize.iWidth==0 || iOverallSize.iHeight==0) + { + iOverallSize = frameInfo.iFrameCoordsInPixels.Size(); + if (iOverallSize.iWidth==0 || iOverallSize.iHeight==0) + { + iEikonEnv->InfoMsg(_L("Invalid image dimensions.")); + User::Leave(KErrCorrupt); + } + } + + iAnimating = (frameInfo.iDelay != TTimeIntervalMicroSeconds(0) || IsMngImage(iLoadUtil)); + + iFrameNumber = 0; + + iTime.HomeTime(); + } + +void CVideoAppUi::ExtractFrameL() + { + if (iLoadFileName.Length() < KShortestPossiblePath) + return; + + ASSERT(iLoadUtil); + + Cancel(); + + TInt frameCount = iLoadUtil->FrameCount(); + + if (iFrameNumber >= frameCount) + iFrameNumber = 0; + + CEikDialog* dialog = new(ELeave) CVideoCurrentFrameDialog(iFrameNumber,frameCount); + if (!dialog->ExecuteLD(R_VIDEO_FRAME_DIALOG)) + return; + + StartFrameOpen(ELoading); + } + +void CVideoAppUi::StartFrameOpen(TState aNextState, TBool aSizeFrame) + { + TRAPD(error, DoStartFrameOpenL(aSizeFrame)); + if (error!=KErrNone) + iWalker->SelfComplete(error); + iState = aNextState; // what ever happens we go to next state, and will handle any error there + } + +void CVideoAppUi::DoStartFrameOpenL(TBool aSizeFrame) + { + ASSERT(iLoadUtil); // should be true by now + ASSERT(!iWalker->IsActive()); // we are going to use it + + ASSERT(iFrameNumber>=0 && iFrameNumberFrameCount()); + + // Set up extensions + if ( iClippingRect.IsEmpty() ) + { + TRAPD(err, iLoadUtil->SetClippingRectL(NULL)); + // Plugin may not support the call at all + if(err != KErrNone && err != KErrNotSupported) + { + User::Leave(err); + } + } + else + { + TRAPD(err,iLoadUtil->SetClippingRectL((iUseExtensions) ? &iClippingRect : NULL )); + // Plugin may not support the call at all + if(err == KErrNotSupported) + { + iEikonEnv->InfoMsg(_L("Clipping Not Supported using this codec.")); + } + } + + TImageConvScaler* scaler = NULL; + TRAPD(err,scaler = iLoadUtil->ScalerL()); + if ( err == KErrNone ) + { + scaler->SetScalingL( (iUseExtensions) ? iScalingCoefficient : -1 , iScalingQuality); + } + else if ( iScalingCoefficient != -1 && err == KErrNotSupported ) + { + iEikonEnv->InfoMsg(_L("Scaler extension Not Supported using this codec.")); + } + + + if ( iOperations.Count() ) + { + TImageConvOperation* operation = NULL; + TRAPD(err,operation = iLoadUtil->OperationL()); + if ( err == KErrNone ) + { + operation->ClearOperationStack(); + + if ( iUseExtensions) + { + for ( TInt i = 0; i < iOperations.Count(); i++) + { + operation->AddOperationL(static_cast(iOperations[i])); + } + } + } + else if ( err == KErrNotSupported ) + { + iEikonEnv->InfoMsg(_L("Operations Not Supported using this codec.")); + } + } + + if (aSizeFrame) + { + TFrameInfo frameInfo = iLoadUtil->FrameInfo(iFrameNumber); + + if (iFrame.Handle() == 0) // Only create the bitmap if we haven't done it already. + { + if ( !iUseNativeDisplayMode && (frameInfo.iFlags & TFrameInfo::ECanDither) ) + User::LeaveIfError(iFrame.Create(TSize(0,0),iAppView->DisplayMode())); + else + User::LeaveIfError(iFrame.Create(TSize(0,0),frameInfo.iFrameDisplayMode)); + } + + // with 16MA and 16MAP we don't use the mask anymore, this since the introduction + // with CR894 & CR1111 of alpha channel support in PNG decoding + + if (frameInfo.iFlags & TFrameInfo::ETransparencyPossible && !iDisableMask + && iAppView->DisplayMode() != EColor16MA && iAppView->DisplayMode() != EColor16MAP ) + { + if (iMask.Handle() == 0) + User::LeaveIfError(iMask.Create(TSize(0,0),EGray256)); + } + else + { + if (iMask.Handle()) + iMask.Reset(); + } + + + SetFrameSizeAndPosL(frameInfo.iFrameCoordsInPixels,frameInfo.iOverallSizeInPixels); + } + + ASSERT(iDisableMask && iMask.Handle()==0 || !iDisableMask); // iDisableMask -> iMask.Handle()==0 + ASSERT(iMask.Handle()==0 || iFrame.SizeInPixels()==iMask.SizeInPixels()); // if mask must be same size + + // DEF090667: T: SetDisplayMode causes another file to be opened with wrong size + if(iFrameNumber == 0) + { + iAppView->Reset(ENoDrawNow); + } + + if (iMask.Handle()) + iLoadUtil->Convert(&(iWalker->ActiveStatus()),iFrame,iMask,iFrameNumber); + else + iLoadUtil->Convert(&(iWalker->ActiveStatus()),iFrame,iFrameNumber); + + iViewResized = EFalse; + } + +TBool CVideoAppUi::ExtensionIsSetup() + { + return ( ( !iClippingRect.IsEmpty() ) || Abs(iScalingCoefficient) > 1 || iOperations.Count() ); + } + +void CVideoAppUi::PlayClipL() + { + iFrameNumber = 0; + iTime.HomeTime(); + + StartFrameOpen(EPlaying); + } + +void CVideoAppUi::SaveAsL() + { + if (iSaveFileName.Length() < KShortestPossiblePath) + iSaveFileName = KDefPath; + + Cancel(); + + CEikDialog* dialog = new(ELeave) CVideoSaveAsDialog(&iSaveFileName,iSaveInfo,iEncodeOperations,iCreateThumbnail,iSaveAsEXIF); + if (!dialog->ExecuteLD(R_VIDEO_FILE_SAVEAS_DIALOG)) + return; + iEikonEnv->FsSession().Delete(iSaveFileName); + + delete iFrameImageData; iFrameImageData = NULL; + + const TUid imageType = iSaveInfo.iImageTypeUid; + TImageDataBlock *imageData = NULL; + TFrameDataBlock *frameData = NULL; + + if(imageType == KImageTypeBMPUid) + { + imageData = new (ELeave) TBmpImageData; + TBmpImageData* data = STATIC_CAST(TBmpImageData*, imageData); + switch (iSaveInfo.iBpp) + { + case 0: data->iBitsPerPixel = 1; break; + case 2: data->iBitsPerPixel = 4; break; + case 3: data->iBitsPerPixel = 8; break; + case 6: data->iBitsPerPixel = 24; break; + default: ASSERT(EFalse); break; + } + } + else if(imageType == KImageTypeGIFUid) + {// gif does not have encoding options + } + else if(imageType == KImageTypeJPGUid) + { + imageData = new (ELeave) TJpegImageData; + TJpegImageData* data = STATIC_CAST(TJpegImageData*, imageData); + if (!iSaveInfo.iColor) + data->iSampleScheme = TJpegImageData::EMonochrome; + else + data->iSampleScheme = TJpegImageData::TColorSampling(3 - iSaveInfo.iSampling); + data->iQualityFactor = iSaveInfo.iQualityFactor; + } + else if(imageType == KImageTypeMBMUid) + { + frameData = new (ELeave) TMbmEncodeData; + TMbmEncodeData* data = STATIC_CAST(TMbmEncodeData*, frameData); + switch (iSaveInfo.iBpp) + { + case 0: data->iDisplayMode = EGray2; break; + case 1: data->iDisplayMode = EGray4; break; + case 2: data->iDisplayMode = iSaveInfo.iColor ? EColor16 : EGray16; break; + case 3: data->iDisplayMode = iSaveInfo.iColor ? EColor256 : EGray256; break; + case 4: data->iDisplayMode = EColor4K; break; + case 5: data->iDisplayMode = EColor64K; break; + case 6: data->iDisplayMode = EColor16M; break; + case 7: data->iDisplayMode = EColor16MU; break; + default: ASSERT(EFalse); break; + } + } + else if(imageType == KImageTypePNGUid) + { + frameData = new (ELeave) TPngEncodeData; + TPngEncodeData* data = STATIC_CAST(TPngEncodeData*, frameData); + // bpp + switch (iSaveInfo.iBpp) + { + case 0: data->iBitsPerPixel = 1; break; // 1 bpp + case 1: data->iBitsPerPixel = 2; break; // 2 bpp + case 2: data->iBitsPerPixel = 4; break; // 4 bpp + case 3: data->iBitsPerPixel = 8; break; // 8 bpp + case 6: data->iBitsPerPixel = 24; break; // 24 bpp + default: ASSERT(EFalse); break; // unsupported bit depth + } + // colour or grayscale? + data->iColor = iSaveInfo.iColor; + // compression level + switch (iSaveInfo.iCompression) + { + case 0: + data->iLevel = TPngEncodeData::EDefaultCompression; + break; + case 1: + data->iLevel = TPngEncodeData::ENoCompression; + break; + case 2: + data->iLevel = TPngEncodeData::EBestSpeed; + break; + case 3: + data->iLevel = TPngEncodeData::EBestCompression; + break; + default: // unsupported compression + ASSERT(EFalse); + break; + } + } + else + { + //custom encoder + } + + if (frameData) + CleanupStack::PushL(frameData); + + if (imageData) + CleanupStack::PushL(imageData); + + delete iSaveUtil; iSaveUtil = NULL; + if ( iSaveAsEXIF && (imageType == KImageTypeJPGUid) ) + { + iSaveUtil = CJPEGExifEncoder::FileNewL(iCoeEnv->FsSession(), iSaveFileName, CImageEncoder::EOptionNone, imageType); + // force creation of metadata - this will cause save as EXIF rather than JFIF + MExifMetadataWriter* metaData=static_cast(iSaveUtil)->ExifMetadata(); + } + else + { + iSaveUtil = CImageEncoder::FileNewL(iCoeEnv->FsSession(), iSaveFileName, CImageEncoder::EOptionNone, imageType); + } + + + ASSERT(iFrameImageData==NULL); // deleted above + if (imageData) + { + iFrameImageData = CFrameImageData::NewL(); + + User::LeaveIfError(iFrameImageData->AppendImageData(imageData)); + CleanupStack::Pop(); // imageData - ownership now passed to iFrameImageData + } + + if (frameData) + { + if (iFrameImageData == NULL) + iFrameImageData = CFrameImageData::NewL(); + + User::LeaveIfError(iFrameImageData->AppendFrameData(frameData)); + CleanupStack::Pop(); // frameData - ownership now passed to iFrameImageData + } + + if (iCreateThumbnail) + { + iSaveUtil->SetThumbnail(iCreateThumbnail); + } + + if ( iEncodeOperations.Count() ) + { + TImageConvOperation* operation = NULL; + TRAPD(err, operation = iSaveUtil->OperationL()); + if ( err == KErrNone ) + { + operation->ClearOperationStack(); + + for ( TInt i = 0; i < iEncodeOperations.Count(); i++) + { + operation->AddOperationL(static_cast(iEncodeOperations[i])); + } + } + } + + StartFrameSave(); + } + +void CVideoAppUi::DisplayModeL() + { + Cancel(); + TDisplayMode displayMode = iAppView->DisplayMode(); + CEikDialog* dialog = new(ELeave) CVideoDisplayModeDialog(displayMode,iUseNativeDisplayMode); + if (dialog->ExecuteLD(R_VIDEO_DISPLAY_MODE_DIALOG)) + { + if ( iUseNativeDisplayMode && iLoadUtil ) + { + TFrameInfo frameInfo = iLoadUtil->FrameInfo(0); + displayMode = frameInfo.iFrameDisplayMode; + } + + iAppView->SetDisplayModeL(displayMode, &iFrame); + } + } + +void CVideoAppUi::BackgroundColorL() + { + Cancel(); + TInt backgroundColor = iBackgroundColor; + TBool override = iOverrideBackgroundColor; + CEikDialog* dialog = new(ELeave) CVideoBackgroundColorDialog(backgroundColor, override); + if (dialog->ExecuteLD(R_VIDEO_BACKGROUND_COLOR_DIALOG)) + { + iBackgroundColor = backgroundColor; + iOverrideBackgroundColor = override; + if (iOverrideBackgroundColor) + { + iAppView->SetBackgroundColor(TRgb::Color16(iBackgroundColor), ENoDrawNow); + iAppView->Clear(ENoDrawNow); + //redraw without reloading + if (iMask.Handle()==0) + iAppView->DrawImage(&iFrame, iOffset, EDrawNow); + else + iAppView->DrawImage(&iFrame, &iMask, iOffset, EDrawNow); + } + } + } + +void CVideoAppUi::StreamPlayL(TFileType aFileType, TBool aMultiFrameStreaming) + { + Cancel(); + iLastFileType = aFileType; + iMultiFrameStreaming = aMultiFrameStreaming; + + if (iLoadFileName.Length() < 4) + iLoadFileName = KDefPath; + CEikDialog* dialog = new(ELeave) CEikFileOpenDialog(&iLoadFileName); + if (!dialog->ExecuteLD(R_EIK_DIALOG_FILE_OPEN)) + return; + + delete iLoadUtil; iLoadUtil = NULL; + + User::Free(REINTERPRET_CAST(TAny*,CONST_CAST(TUint8*, iStreamBuffer.Ptr()))); + iStreamBuffer.Set(NULL, 0, 0); + + RFile file; + User::LeaveIfError(file.Open(iEikonEnv->FsSession(), iLoadFileName, EFileShareReadersOnly|EFileStream|EFileRead)); + CleanupClosePushL(file); + TInt fileSize; + User::LeaveIfError(file.Size(fileSize)); + iStreamBuffer.Set(STATIC_CAST(TUint8 *, User::AllocL(fileSize)), 0, fileSize); + User::LeaveIfError(file.Read(iStreamBuffer)); + CleanupStack::PopAndDestroy(); // file + + iEikonEnv->BusyMsgL(_L("Busy...")); + + // NB. State machine assumes no leaves after this point + + ASSERT(!iStreamGen->IsActive()); // no async behav should be going on at this point + ASSERT(!iWalker->IsActive()); + + // initialize the buffer + iStreamBuffer.SetLength(0); // data is in buffer, and we increase length to simulate data arriving + User::LeaveIfError(ExtendStreamBuffer()); + + iState = EStreamOpening; + } + +TInt CVideoAppUi::ExtendStreamBuffer() + { +// ASSERT(iStreamBuffer.Length()=99) + waitTime = Math::Rand(iStreamSeed) % 5000000; + else + waitTime = Math::Rand(iStreamSeed) % 50000; + + iStreamTimer.After(iStreamGen->ActiveStatus(), waitTime); + iSourceHasGrown = ETrue; + +#if defined(_DEBUG) && defined(__ENABLE_DEBUG_OUTPUT) + RDebug::Print(_L("ExtendingStreamBuffer(%d,%d->%d)"), increment, waitTime, newSize); +#endif + + return KErrNone; + } + +void CVideoAppUi::FrameInfoL() + { + if (iFrame.Handle() == 0) + return; + + Cancel(); + + const TInt frameCount = iLoadUtil->FrameCount(); + if(iFrameNumber >= frameCount) + iFrameNumber = frameCount-1; + + HBufC* infoBuffer = HBufC::NewLC(KInfoBufferSize); + TPtr info(infoBuffer->Des()); + + CFrameInfoStrings *frameInfoStrings = iLoadUtil->FrameInfoStringsLC(iFrameNumber); + TInt count = frameInfoStrings->Count(); + TInt index; + for (index=0; indexString(index); + info.Append(frameInfoString); + info.Append(TChar(CEditableText::ELineBreak)); + } + + HBufC* imageComments = HBufC::NewLC(0); + TInt numImageComments = iLoadUtil->NumberOfImageComments(); + for (index = 0; indexImageCommentL(index); + CleanupStack::PushL(nextComment); + + TPtr commentTPtr(nextComment->Des()); + ReplaceNewlinesWithLineBreaks(commentTPtr); + + if (index==0) + { + // first go through, so should have nothing in comments - just assign + ASSERT(imageComments->Length()==0); + imageComments = imageComments->ReAllocL(nextComment->Length()); + *imageComments = *nextComment; + } + else + { + // append line break and then new comments + imageComments = imageComments->ReAllocL(imageComments->Length() + nextComment->Length() + 1); // 1 for linebreak character + TPtr imageCommentsPtr(imageComments->Des()); + imageCommentsPtr.Append(TChar(CEditableText::ELineBreak)); + imageCommentsPtr.Append(*nextComment); + } + CleanupStack::PopAndDestroy(); // nextComment + CleanupStack::Pop(); // old imageComments (already deleted by ReAlloc) + CleanupStack::PushL(imageComments); + } + + HBufC* frameComments = HBufC::NewLC(0); + TInt numFrameComments = iLoadUtil->NumberOfFrameComments(iFrameNumber); + for (index = 0; indexFrameCommentL(iFrameNumber, index); + CleanupStack::PushL(nextComment); + + TPtr commentTPtr(nextComment->Des()); + ReplaceNewlinesWithLineBreaks(commentTPtr); + + if (index==0) + { + // first go through, so should have nothing in comments - just assign + ASSERT(frameComments->Length()==0); + frameComments = frameComments->ReAllocL(nextComment->Length()); + *frameComments = *nextComment; + } + else + { + // append line break and then new comments + frameComments->ReAllocL(frameComments->Length() + nextComment->Length() + 1); // 1 for linebreak character + TPtr frameCommentsPtr(frameComments->Des()); + frameCommentsPtr.Append(TChar(CEditableText::ELineBreak)); + frameCommentsPtr.Append(*nextComment); + } + CleanupStack::PopAndDestroy(); // nextComment + CleanupStack::Pop(); // old frameComments (already deleted by ReAlloc) + CleanupStack::PushL(frameComments); + } + + CEikDialog* dialog = new(ELeave) CFrameInfoDialog(info, *imageComments, *frameComments); + dialog->ExecuteLD(R_VIDEO_INFO_DIALOG); + + CleanupStack::PopAndDestroy(4); // frameComments, imageComments, frameInfoStrings + infoBuffer + } + +void CVideoAppUi::FrameRotateL(TBool aClockwise) + { + ASSERT(iState == EIdle); + CBitmapRotator::TRotationAngle angle = aClockwise ? + CBitmapRotator::ERotation90DegreesClockwise : + CBitmapRotator::ERotation270DegreesClockwise; + if (iMask.Handle() != 0) + { + iRotateAngle = angle; //keep for second phase + iRotator->Rotate(&(iWalker->ActiveStatus()), iMask, angle); + iState = ERotatingMask; + } + else + { + iRotator->Rotate(&(iWalker->ActiveStatus()), iFrame, angle); + iState = ERotating; + } + iViewResized = EFalse; + } + +void CVideoAppUi::FrameMirrorL(TBool aHorizontalAxis) + { + ASSERT(iState == EIdle); + CBitmapRotator::TRotationAngle angle = aHorizontalAxis ? + CBitmapRotator::EMirrorHorizontalAxis : + CBitmapRotator::EMirrorVerticalAxis; + if (iMask.Handle() != 0) + { + iRotateAngle = angle; //keep for second phase + iRotator->Rotate(&(iWalker->ActiveStatus()), iMask, angle); + iState = ERotatingMask; + } + else + { + iRotator->Rotate(&(iWalker->ActiveStatus()), iFrame, angle); + iState = ERotating; + } + iViewResized = EFalse; + } + +void CVideoAppUi::ZoomFrameL(TBool aZoomIn) + { + TSize size(iFrame.SizeInPixels()); + const TSize adjust(size.iWidth / KScaleFactor, size.iHeight / KScaleFactor); + + if (aZoomIn) + size += adjust; + else + size -= adjust; + + Cancel(); + + TFrameInfo frameInfo = iLoadUtil->FrameInfo(iFrameNumber); + + if (!(frameInfo.iFlags&TFrameInfo::EFullyScaleable)) + { + if (iMask.Handle()!=0) + { + iScaleSize = size; // keep for second scale action + iScaler->Scale(&(iWalker->ActiveStatus()),iMask,size); + iViewResized = EFalse; + iState = EScalingMask; + } + else + { + iScaler->Scale(&(iWalker->ActiveStatus()),iFrame,size); + iViewResized = EFalse; + iState = EScaling; + } + } + else + { + SetFrameSizeAndPosL(frameInfo.iFrameCoordsInPixels,size); + + if (!(frameInfo.iFlags&TFrameInfo::ECanDither)) + { + iFrame.Reset(); + User::LeaveIfError(iFrame.Create(TSize(0,0),frameInfo.iFrameDisplayMode)); // We will dither later + } + +#if !defined(__CLEAR_BITMAPS_FIRST) + if (iFrame.SizeInPixels() != size) +#endif + { + #if defined(__CLEAR_BITMAPS_FIRST) + User::LeaveIfError(iFrame.Resize(TSize(0,0))); + #endif + User::LeaveIfError(iFrame.Resize(size)); + } + + if (iMask.Handle()) + { + if (iMask.SizeInPixels() != size) + User::LeaveIfError(iMask.Resize(size)); + #if defined(__CLEAR_BITMAPS_FIRST) + // set mask to black, so it is opaque and by default nothing is drawn + CFbsBitmapDevice* device = CFbsBitmapDevice::NewL(&iMask); + CleanupStack::PushL(device); + CFbsBitGc* bmGc = CFbsBitGc::NewL(); + CleanupStack::PushL(bmGc); + bmGc->Activate(device); + bmGc->SetPenStyle(CGraphicsContext::ENullPen); + bmGc->SetBrushStyle(CGraphicsContext::ESolidBrush); + bmGc->SetBrushColor(KRgbBlack); + const TRect drawRect(TPoint(0,0), iMask.SizeInPixels()); + bmGc->DrawRect(drawRect); + CleanupStack::PopAndDestroy(2); + #endif + } + + StartFrameOpen(ELoading, EFalse); + } + } + +void CVideoAppUi::StartFrameSave() + { + ASSERT(iSaveUtil); // should be true by now + ASSERT(iState==EIdle); + ASSERT(!iWalker->IsActive()); // we are going to use it + iSaveUtil->Convert(&(iWalker->ActiveStatus()),iFrame,iFrameImageData); + iState = ESaving; + } + +void CVideoAppUi::DrawConvertedFrameL() + { + ASSERT(iDisableMask && iMask.Handle()==0 || !iDisableMask); // iDisableMask -> iMask.Handle()==0 + ASSERT(iMask.Handle()==0 || iFrame.SizeInPixels()==iMask.SizeInPixels()); // if mask must be same size + + TBool fullRedrawReq = EFalse; + if (!iViewResized) + { + TFrameInfo frameInfo = iLoadUtil->FrameInfo(iFrameNumber); + TRgb backgroundColor = iOverrideBackgroundColor ? TRgb::Color16(iBackgroundColor) : frameInfo.iBackgroundColor; + fullRedrawReq = iAppView->SetBackgroundColor(backgroundColor, ENoDrawNow); + if (iState == EScaling || iState == ERotating) + { + // size and center based on bitmap, rather than the official image size + TBool resized = iAppView->ResizeL(iFrame.SizeInPixels(), ETrue, ENoDrawNow); + if (resized) + iAppView->Center(ENoDrawNow); + fullRedrawReq = fullRedrawReq || resized; + } + else if (!iAnimating || iFrameNumber==0) + { + TBool resized = iAppView->ResizeL(iImageDisplaySize, ETrue, ENoDrawNow); + // implies Resize + + // PDEF088116: TImageViewer USER 0 with certain animated gifs + if(frameInfo.iFlags & TFrameInfo::EUsesFrameSizeInPixels) + { + if(iFrame.SizeInPixels() != frameInfo.iFrameSizeInPixels) + { + iFrame.Resize(frameInfo.iFrameSizeInPixels); + } + } + //Resize iFrame to iImageDisplaySize if they are different + else if (iFrame.SizeInPixels() != iImageDisplaySize) + { + iFrame.Resize(iImageDisplaySize); + } + + if (resized) + iAppView->Center(ENoDrawNow); + else if (IsMngImage(iLoadUtil) && (iLastFrameFlags & TFrameInfo::ERestoreToBackground)) + { + iAppView->Clear(EFalse, EDrawNow); + } + fullRedrawReq = fullRedrawReq || resized; + } + else if (iFrameNumber > 0 && iLastFrameFlags & TFrameInfo::ERestoreToBackground + || iState != EPlaying && iState != EStreamDecoding && iFrameNumber-1!=iPrevFrameNumber) + { + iAppView->Clear(EFalse, EDrawNow); + ASSERT(iAnimating); // should be true given above, avoids complicating below + if (iState != EPlaying && iState != EStreamDecoding && iFrameNumber-1!=iPrevFrameNumber) + fullRedrawReq = ETrue; + // usually will want to redraw _whole_ bitmap area - otherwise we only + // redraw that part of the bitmap we DrawImage to + // exception is when we are extracting frames in the correct sequence + } + else if (iAnimating && (iState==EPlaying||iState==EStreamDecoding)) + { + // if animating and playing, should have frame greater than 0 and no restore to background - or will trigger above + ASSERT(! (iLastFrameFlags & TFrameInfo::ERestoreToBackground)); + ASSERT(iFrameNumber>0 && iFrameNumber-1==iPrevFrameNumber); + fullRedrawReq = EFalse; // don't redraw full - even if background changed, want to just redraw our bit + } + iViewResized = ETrue; + } + + if (iMask.Handle()==0) + iAppView->DrawImage(&iFrame, iOffset, fullRedrawReq?ENoDrawNow:EDrawNow); + else + iAppView->DrawImage(&iFrame, &iMask, iOffset, fullRedrawReq?ENoDrawNow:EDrawNow); + + if (fullRedrawReq) + iAppView->DrawNow(); + } + +void CVideoAppUi::HandleConvertCompleteL() + { + DrawConvertedFrameL(); + + TFrameInfo frameInfo = iLoadUtil->FrameInfo(iFrameNumber); + + iLastFrameFlags = frameInfo.iFlags; + iPrevFrameNumber = iFrameNumber; + + if (iAnimating && iState==EPlaying || + iState==EStreamDecoding && (iMultiFrameStreaming||iAnimating)) + { + ASSERT(!iWalker->IsActive()); // we will use it again + TBool mustSelfComplete=EFalse; + if ((iAnimating && frameInfo.iDelay > TTimeIntervalMicroSeconds(0))||iMultiFrameStreaming) + { + TTime endTime; + endTime.HomeTime(); + + TTimeIntervalMicroSeconds timeTaken = endTime.MicroSecondsFrom(iTime); + if (frameInfo.iDelay > timeTaken) + { + TInt64 delay = frameInfo.iDelay.Int64() - timeTaken.Int64(); + TInt delayPeriod = I64LOW(delay); + if (delayPeriod<0) + delayPeriod=0; // can get negative if we took longer on the streaming than this + iTimer.After(iWalker->ActiveStatus(), delayPeriod); + } + else if(iMultiFrameStreaming) + { + TInt delay = KDefaultStreamDelay - I64LOW(timeTaken.Int64()); + if (delay<0) + delay=0; // can get negative if we took longer on the streaming than this + iTimer.After(iWalker->ActiveStatus(), delay); + } + else + mustSelfComplete=ETrue; + } + else + mustSelfComplete=ETrue; + if (mustSelfComplete) + iWalker->SelfComplete(KErrNone); + if (iState==EPlaying) + iState = EPlayingWait; + else + { + ASSERT(iState==EStreamDecoding); + iState = EStreamDecodeWait; + } + } + else if (iOpeningFolder) + LoadFolderWait(); + else + { + iEikonEnv->BusyMsgCancel(); + Cancel(); // cancel any background streaming + iState = EIdle; + } + } + +void CVideoAppUi::RunL(CVideoWalker* aWalker, TInt aStatus) + { + ASSERT(aWalker==iWalker || aWalker==iStreamGen); // ones we know about + +#if defined(_DEBUG) && defined(__ENABLE_DEBUG_OUTPUT) + RDebug::Print(_L("RunL(%x,%d,%d)(%x,%x)"), aWalker, aStatus, iState, iWalker, iStreamGen); +#endif + + switch (iState) + { + case EIdle: + ASSERT(EFalse); // should not happen + break; + case ELoading: + case EPlaying: + case EScaling: + case ERotating: + { + ASSERT(aWalker==iWalker); + TInt error = aStatus; + if (error==KErrNone) + TRAP(error, HandleConvertCompleteL()); + if (error!=KErrNone) + HandleRunError(aWalker, error); + } + break; + case ERotatingMask: + { + ASSERT(aWalker == iWalker); + if (aStatus==KErrNone) + { + // having done mask, kick off rotate the image itself + iRotator->Rotate(&(iWalker->ActiveStatus()), iFrame, iRotateAngle); + iState = ERotating; + } + else + { + HandleRunError(aWalker, aStatus); + } + break; + } + case EScalingMask: + { + ASSERT(aWalker==iWalker); + if (aStatus==KErrNone) + { + // having done mask, kick off scale of normal + iScaler->Scale(&iWalker->ActiveStatus(), iFrame, iScaleSize); + iState = EScaling; + } + else + HandleRunError(aWalker, aStatus); + } + break; + case EPlayingWait: + { + ASSERT(iWalker==aWalker); + iTime.HomeTime(); // whatever reset the time here + if (aStatus!=KErrNone) + HandleRunError(aWalker, aStatus); + else if (iFrameNumber < iLoadUtil->FrameCount()-1 || (IsMngImage(iLoadUtil)&&HasMoreMngFrames(iLoadUtil)) ) + { + iFrameNumber += ( IsMngImage(iLoadUtil)==EFalse ); + StartFrameOpen(EPlaying); + } + else if (iOpeningFolder) + LoadFolderWait(); + else + { + ASSERT(!iWalker->IsActive() && !iStreamGen->IsActive()); // should have stopped naturally + iEikonEnv->BusyMsgCancel(); + iState = EIdle; + } + } + break; + case ESaving: + { + ASSERT(iWalker==aWalker); + iEikonEnv->BusyMsgCancel(); + iState = EIdle; + if (aStatus!=KErrNone) + HandleRunError(aWalker, aStatus); + } + break; + case EStreamOpening: + { + ASSERT(aWalker==iStreamGen); + TInt error = aStatus; + + if (error==KErrNone) + { + delete iLoadUtil; iLoadUtil = NULL; + + TUid format; + switch (iLastFileType) + { + case EFileTypeOta: + format = KImageTypeOTAUid; + break; + case EFileTypeWbmp: + format = KImageTypeWBMPUid; + break; + default: + format = KNullUid; + } + + TRAP(error, iLoadUtil = CImageDecoder::DataNewL(iCoeEnv->FsSession(), iStreamBuffer, + CImageDecoder::TOptions(iDecoderOptions | CImageDecoder::EOptionAllowZeroFrameOpen), format)); + } + + if (error==KErrUnderflow) + { + error = KErrNone; // clear so we don't hit the error handler below + if (!iStreamGen->IsActive()) + error = ExtendStreamBuffer(); // wait for more input. remain in current state + } + else if (error==KErrNone) + { + if (iLoadUtil->FrameCount()>0) + { + TRAP(error,HandleNewlyOpenedImageL()); + if (error==KErrNone) + TRAP(error,StreamOpenFrameIfPosL()); + } + else + { + // insufficient data, so wait until it comes along + if (!iStreamGen->IsActive()) + error = ExtendStreamBuffer(); // wait for more input. switch to EStreamWaitForFirstFrame + iState = EStreamWaitForFirstFrame; + } + } + + if (error!=KErrNone) + HandleRunError(aWalker, error); + } + break; + case EStreamWaitAndContinue: +#if defined(__BYPASS_CONTINUE_CONVERT) + ASSERT(EFalse); // should not happen when bypassing +#else + { + ASSERT(aWalker==iStreamGen); + + TInt error = aStatus; + + if (error==KErrNone) + { + if ((iStreamBuffer.Length()IsActive()) + error = ExtendStreamBuffer(); // "new data has arrived" + ASSERT(iSourceHasGrown); + ASSERT(iState==EStreamWaitAndContinue); + iLoadUtil->ContinueConvert(&(iWalker->ActiveStatus())); + iSourceHasGrown = EFalse; + iState = EStreamDecoding; + } + + if (error!=KErrNone) + HandleRunError(aWalker, error); + } +#endif + break; + case EStreamWaitForFirstFrame: + { + ASSERT(aWalker==iStreamGen); + + TInt error = aStatus; + + if (error==KErrNone) + { + ASSERT(!iLoadUtil->IsImageHeaderProcessingComplete()); // should not be reading more than we need to know + iLoadUtil->ContinueProcessingHeaderL(); + if (iLoadUtil->FrameCount()>0) + { + TRAP(error,HandleNewlyOpenedImageL()); + if (error==KErrNone) + TRAP(error,StreamOpenFrameIfPosL()); + } + else + { + // insufficient data, so wait until it comes along + if (!iStreamGen->IsActive()) + error = ExtendStreamBuffer(); // wait for more input. stay in same state + } + } + + if (error!=KErrNone) + HandleRunError(aWalker, error); + } + break; + case EStreamWaitForDetails: + { + ASSERT(aWalker==iStreamGen); + TInt error = aStatus; + + if (error==KErrNone) + { + TRAP(error, StreamOpenFrameIfPosL()); + } + if (error!=KErrNone) + HandleRunError(aWalker, error); + } + break; + case EStreamDecoding: + { + ASSERT(aWalker==iWalker || aWalker==iStreamGen); + TInt error = aStatus; + if (aWalker==iWalker) + { + TBool timerActive = iStreamGen->IsActive(); + if (error==KErrNone) + { + TRAP(error, HandleConvertCompleteL()); + } + else if (error==KErrUnderflow && (timerActive || iSourceHasGrown)) + { + // draw partial result to the screen if possible, else set error to KErrNone so we don't stop + TFrameInfo frameInfo = iLoadUtil->FrameInfo(iFrameNumber); + if (!(frameInfo.iFlags & TFrameInfo::EPartialDecodeInvalid)) + { + TRAP(error, DrawConvertedFrameL()); + } + else + error = KErrNone; + + if (error==KErrNone) + { + // wait for more data to arrive before we try again + #if defined(__BYPASS_CONTINUE_CONVERT) + iState = EStreamWaitForDetails; + #else + iState = EStreamWaitAndContinue; + #endif + if(!timerActive) + { // final buffer was added after last Convert()/ContinueConvert() + ASSERT(iStreamBuffer.Length()==iStreamBuffer.MaxLength()); + ASSERT(iSourceHasGrown); + // force a final decode + iStreamTimer.After(iStreamGen->ActiveStatus(),0); + } + } + } + } + else + { + ASSERT(aWalker==iStreamGen); + if (error==KErrNone && iStreamBuffer.Length()FrameCount()-1 || !iLoadUtil->IsImageHeaderProcessingComplete()) + { + iFrameNumber += 1; + TRAP(error,StreamOpenFrameIfPosL()); + } + else + { + Cancel(); // may be required true, eg if there is data after the frame, other AO may be busy + iEikonEnv->BusyMsgCancel(); + iState = EIdle; + } + } + } + else + { + ASSERT(aWalker==iStreamGen); + if (error==KErrNone && iStreamBuffer.Length()Cancel(); + break; + case ESaving: + iSaveUtil->Cancel(); + break; + case EScaling: + case EScalingMask: + iScaler->Cancel(); + break; + case ERotating: + case ERotatingMask: + iRotator->Cancel(); + break; + case EStreamDecodeWait: + case EPlayingWait: // ignore scenario where we self complete - will not get here + case EFolderWait: + iTimer.Cancel(); + break; + default: + ASSERT(EFalse); // unknown state or should not happen + } + } + else + { + ASSERT(aWalker==iStreamGen); + switch (iState) + { + case EStreamOpening: + case EStreamWaitForDetails: + case EStreamWaitAndContinue: + case EStreamDecoding: + case EStreamDecodeWait: + case EStreamWaitForFirstFrame: + iStreamTimer.Cancel(); + break; + default: + ASSERT(EFalse); // unknown state or should not happen + } + } + } + +void CVideoAppUi::HandleRunError(CVideoWalker* /*aWalker*/, TInt aError) + { + Cancel(); + iEikonEnv->BusyMsgCancel(); + iEikonEnv->HandleError(aError); + ASSERT(iState == EIdle); + } + +void CVideoAppUi::StreamOpenFrameIfPosL() + { + if (iFrameNumber >= iLoadUtil->FrameCount()) + { + // Continue processing headers if necessary and only if we are not in the middle of an image conversion. + ASSERT(!iLoadUtil->IsImageHeaderProcessingComplete()); // should not be reading more than we need to know + iLoadUtil->ContinueProcessingHeaderL(); + } + + if (iFrameNumber >= iLoadUtil->FrameCount()) + { + if (iLoadUtil->IsImageHeaderProcessingComplete()) + { + Cancel(); // other AO could still be busy if there were bytes after last frame data + iEikonEnv->BusyMsgCancel(); + iState = EIdle; + } + else + { + // not yet reached the frame header + iState = EStreamWaitForDetails; + if (!iStreamGen->IsActive()) + // this shuld cope with reaching end of stream prematurely : + User::LeaveIfError(ExtendStreamBuffer()); + } + } + else + { + if ((iStreamBuffer.Length()IsActive()) + User::LeaveIfError(ExtendStreamBuffer()); // "new data has arrived" + ASSERT(iSourceHasGrown); + StartFrameOpen(EStreamDecoding); + iSourceHasGrown = EFalse; + } + ASSERT(iState==EIdle||iStreamBuffer.Length()==iStreamBuffer.MaxLength()||iStreamGen->IsActive()); // either we've finished, reached the end or we expect more data + } + +void CVideoAppUi::SetFrameSizeAndPosL(const TRect& aFrameRect,const TSize& aOverallSize) + { + TRect zoomedFrame(aFrameRect); + TSize zoomedSize(aOverallSize); + TSize zoomedOverallSize(iOverallSize); // effectively size on frame 0 + if (aOverallSize.iWidth == 0 || aOverallSize.iHeight == 0) + zoomedSize = aFrameRect.Size(); + + if ( iUseExtensions ) + { + // using PREQ1630 extensions + TInt err = iLoadUtil->GetDestinationSize(zoomedSize,iFrameNumber); + if ( err != KErrNone ) + { + TBuf<256> buf; + buf.Format(_L("GetDestinationSize Error %d"),err); + iEikonEnv->InfoMsg(buf); + } + + User::LeaveIfError(iFrame.Resize(zoomedSize)); + } + else + { + if (iZoomFactor > 0) + { + zoomedFrame.iTl.iX <<= iZoomFactor; + zoomedFrame.iTl.iY <<= iZoomFactor; + zoomedFrame.iBr.iX <<= iZoomFactor; + zoomedFrame.iBr.iY <<= iZoomFactor; + zoomedSize.iWidth <<= iZoomFactor; + zoomedSize.iHeight <<= iZoomFactor; + zoomedOverallSize.iWidth <<= iZoomFactor; + zoomedOverallSize.iHeight <<= iZoomFactor; + } + else if (iZoomFactor < 0) + { + const TInt absZoomFactor = -iZoomFactor; +#if defined(__USE_PURE_SCALING) + const TInt roundingFactor = 0; // set 0 to get pure scaling +#else + const TInt roundingFactor = (1 << absZoomFactor) - 1; +#endif + zoomedFrame.iTl.iX = (zoomedFrame.iTl.iX) >> absZoomFactor; + zoomedFrame.iTl.iY = (zoomedFrame.iTl.iY) >> absZoomFactor; + // zoomedFrame.iBr.iX = (zoomedFrame.iBr.iX + roundingFactor) >> absZoomFactor; + // zoomedFrame.iBr.iY = (zoomedFrame.iBr.iY + roundingFactor) >> absZoomFactor; + + zoomedSize.iWidth = (zoomedSize.iWidth + roundingFactor) >> absZoomFactor; + zoomedSize.iHeight = (zoomedSize.iHeight + roundingFactor) >> absZoomFactor; + + zoomedFrame.iBr = zoomedFrame.iTl + zoomedSize; + + zoomedOverallSize.iWidth = (zoomedOverallSize.iWidth + roundingFactor) >> absZoomFactor; + zoomedOverallSize.iHeight = (zoomedOverallSize.iHeight + roundingFactor) >> absZoomFactor; + } + +#if !defined(__CLEAR_BITMAPS_FIRST) + if (iFrame.SizeInPixels() != zoomedFrame.Size()) +#endif + { +#if defined(__CLEAR_BITMAPS_FIRST) + // resize via 0 so that we clear original + User::LeaveIfError(iFrame.Resize(TSize(0,0))); +#endif + User::LeaveIfError(iFrame.Resize(zoomedSize)); + } + } + + if (iMask.Handle()) + { + if (iMask.SizeInPixels() != zoomedFrame.Size()) + User::LeaveIfError(iMask.Resize(zoomedSize)); + #if defined(__CLEAR_BITMAPS_FIRST) + // set mask to black, so it is opaque and by default nothing is drawn + CFbsBitmapDevice* device = CFbsBitmapDevice::NewL(&iMask); + CleanupStack::PushL(device); + CFbsBitGc* bmGc = CFbsBitGc::NewL(); + CleanupStack::PushL(bmGc); + bmGc->Activate(device); + bmGc->SetPenStyle(CGraphicsContext::ENullPen); + bmGc->SetBrushStyle(CGraphicsContext::ESolidBrush); + bmGc->SetBrushColor(KRgbBlack); + const TRect drawRect(TPoint(0,0), zoomedSize); + bmGc->DrawRect(drawRect); + CleanupStack::PopAndDestroy(2); + #endif + } + + iImageDisplaySize = zoomedSize; + iOffset = zoomedFrame.iTl; + + ASSERT(iMask.Handle()==0 || iFrame.SizeInPixels()==iMask.SizeInPixels()); // if mask must be same size + } + +void CVideoAppUi::ReplaceNewlinesWithLineBreaks(TDes& aText) + { + TInt pos=0; + + for (;;) + { + if (pos >= aText.Length()) // will occur if last character in comment is new line + break; + const TPtrC restOfText(aText.Mid(pos)); + TInt posOfNextNewLine = restOfText.Locate(TChar('\n')); + if (posOfNextNewLine<0) // no more new lines in text + break; + posOfNextNewLine += pos; // position relative to whole descriptor + aText[posOfNextNewLine] = CEditableText::ELineBreak; + pos = posOfNextNewLine + 1; // next cycle, start at next character + } + } + +// update crop region +void CVideoAppUi::UpdateClippingRect(TUint code) + { + TFrameInfo frameInfo; + if ( iLoadUtil ) + { + switch (code) + { + case EKeyLeftArrow: + iClippingRect.Move(-Min(iClippingRect.Width(),iClippingRect.iTl.iX),0); + break; + case EKeyRightArrow: + { + const TFrameInfo& frameInfo = iLoadUtil->FrameInfo(iFrameNumber); + iClippingRect.Move(Min(iClippingRect.Width(),frameInfo.iOverallSizeInPixels.iWidth-iClippingRect.iBr.iX),0); + } + break; + case EKeyUpArrow: + iClippingRect.Move(0,-Min(iClippingRect.Height(),iClippingRect.iTl.iY)); + break; + case EKeyDownArrow: + { + const TFrameInfo& frameInfo = iLoadUtil->FrameInfo(iFrameNumber); + iClippingRect.Move(0,Min(iClippingRect.Height(),frameInfo.iOverallSizeInPixels.iHeight-iClippingRect.iBr.iY)); + } + break; + } + } + LoadFileL(); + } +// +// CVideoAppView +// + +CVideoAppView* CVideoAppView::NewL(const TRect& aRect) + { + CVideoAppView* self = new (ELeave) CVideoAppView; + CleanupStack::PushL(self); + self->ConstructL(aRect); + CleanupStack::Pop(); + return self; + } + +CVideoAppView::CVideoAppView(): + CCoeControl() + {} + +void CVideoAppView::ConstructL(const TRect& /*aRect*/) + { + CreateWindowL(); +#if defined(__WINS__) + Window().SetRequiredDisplayMode(SystemGc().Device()->DisplayMode()); +#endif + iDisplayMode = Window().DisplayMode(); + EnableDragEvents(); + SetExtentToWholeScreen(); + + iBmBuffer = new (ELeave) CWsBitmap(iCoeEnv->WsSession()); + ActivateL(); + } + +CVideoAppView::~CVideoAppView() + { + delete iBmGc; + delete iBmDevice; + delete iBmBuffer; + } + +void CVideoAppView::Draw(const TRect& aRect) const + { + CWindowGc& gc = SystemGc(); + TRect drawRect=Rect(); + + ASSERT(!iBitmapValid || iBmRect.Size() == iBmBuffer->SizeInPixels()); // either bitmap not valid or size of bmrect is same as the buffer + + if (iBitmapValid) + { + // if the required rect includes some background, then draw it + // check is to see if the passed aRect is a pure subset of the bitmap rect + TRect intersection(aRect); + intersection.Intersection(iBmRect); + if (intersection != aRect) + { + gc.SetPenStyle(CGraphicsContext::ENullPen); // solid background rect + gc.SetBrushStyle(CGraphicsContext::ESolidBrush); + gc.SetBrushColor(KRgbWhite); + gc.DrawRect(drawRect); + TRect frame(iBmRect); // draw a frame one pixel larger than bitmap + frame.Grow(1,1); + gc.SetBrushStyle(CGraphicsContext::ENullBrush); + gc.SetPenStyle(CGraphicsContext::ESolidPen); + gc.DrawRect(frame); + } + // now if there is some bitmap to be drawn... + if (!intersection.IsEmpty()) + { + gc.BitBlt(iBmRect.iTl, iBmBuffer); + } + } + else + { + gc.Clear(); + drawRect.Shrink(10,10); + gc.DrawRect(drawRect); + gc.DrawLine(drawRect.iTl,drawRect.iBr); + gc.DrawLine(TPoint(drawRect.iTl.iX,drawRect.iBr.iY),TPoint(drawRect.iBr.iX,drawRect.iTl.iY)); + } + } + +void CVideoAppView::Reset(TDrawNow aDrawNow) + { + iBmBuffer->Reset(); + iBitmapValid = EFalse; + if (aDrawNow!=ENoDrawNow) + DrawNow(); + } + +void CVideoAppView::DrawImage(CFbsBitmap* aBitmap, const TPoint& aOffset, TDrawNow aDrawNow) + { + DrawImage(aBitmap, NULL, aOffset, aDrawNow); + } + +void CVideoAppView::DrawImage(CFbsBitmap* aBitmap, CFbsBitmap* aMask, const TPoint& aOffset, TDrawNow aDrawNow) + { + ASSERT(iBitmapValid && iBmBuffer->Handle()); // should only be called when size setup properly + ASSERT(aMask==NULL || aBitmap->SizeInPixels()==aMask->SizeInPixels()); + // if we have a mask, assumed to be the same size as the original + + const TPoint screenOffset = iBmRect.iTl + aOffset; // relative to screen instead of iBmRect + const TRect bitmapRect (screenOffset, aBitmap->SizeInPixels()); // the rect for this bitmap + +#if defined(_DEBUG) + TRect intersection (bitmapRect); // check that this rect is same or smaller than the bitmap + ASSERT(iBmRect.Size() == iBmBuffer->SizeInPixels()); + intersection.Intersection(iBmRect); + ASSERT(intersection==bitmapRect); +#endif + + // first draw to bitmap buffer + if (aMask) + iBmGc->BitBltMasked(aOffset, aBitmap, TRect(aBitmap->SizeInPixels()), aMask, EFalse); + else + iBmGc->BitBlt(aOffset, aBitmap); + + // if required, also draw to screen + if (aDrawNow!=ENoDrawNow) + { + ActivateGc(); + CWindowGc& gc = SystemGc(); + if (aMask) + gc.BitBltMasked(screenOffset, aBitmap, TRect(aBitmap->SizeInPixels()), aMask, EFalse); + else + gc.BitBlt(screenOffset, aBitmap); + DeactivateGc(); + } + } + +TBool CVideoAppView::ResizeL(const TSize& aNewSize, TBool aClear, TDrawNow aDrawNow) + { + //Resize iBmBuffer to iBmRect where iBmBuffer holds the aNewSize. + if(iBmRect.Size() != aNewSize) + { + iBmBuffer->Resize(iBmRect.Size()); + } + ASSERT(!iBitmapValid || iBmRect.Size() == iBmBuffer->SizeInPixels()); // either bitmap not valid or size of bmrect is same as the buffer + if (iBitmapValid && aNewSize==iBmRect.Size()) + { + // special cases where we don't actually modify the size + if (aDrawNow!=ENoDrawNow) + DrawNow(); + return EFalse; + } + + CFbsBitmap* tempBuffer = NULL; + + TBool preserveOrig = !aClear && iBitmapValid; + + if (preserveOrig) + { + // tempBuffer becomes copy of original + tempBuffer = new (ELeave) CWsBitmap(iCoeEnv->WsSession()); + CleanupStack::PushL(tempBuffer); + User::LeaveIfError(tempBuffer->Duplicate(iBmBuffer->Handle())); + } + + ResizeBufferL(aNewSize, iDisplayMode); + // resize bitmap + + iBitmapValid = ETrue; + iBmRect.SetRect(iBmRect.iTl, aNewSize); // rect with same Tl but new size + ASSERT(iBmRect.Size() == iBmBuffer->SizeInPixels()); // check resized bitmap OK + + if (preserveOrig) + { + // draw original back at new size + EnsureSizeInTwipsSet(tempBuffer); + EnsureSizeInTwipsSet(iBmBuffer); + iBmGc->DrawBitmap(TPoint(0,0), tempBuffer); + CleanupStack::PopAndDestroy(); // tempBuffer + } + else + Clear(EFalse, ENoDrawNow); // get background correct colour + + if (aDrawNow!=ENoDrawNow) + DrawNow(); + + return ETrue; + } + +void CVideoAppView::ResizeBufferL(const TSize& aNewSize, TDisplayMode aDisplayMode) + { + delete iBmGc; iBmGc = NULL; + delete iBmDevice; iBmDevice = NULL; + User::LeaveIfError(iBmBuffer->Create(aNewSize, aDisplayMode)); + iBmDevice = CFbsBitmapDevice::NewL(iBmBuffer); + iBmGc = CFbsBitGc::NewL(); + iBmGc->Activate(iBmDevice); + } + +void CVideoAppView::EnsureSizeInTwipsSet(CFbsBitmap* aBitmap) const + { + // ensure the bitmap has twips size set - this allows us to use DrawBitmap + // note this does not itself resize the bitmap - size in pixels remains unchanged + TSize size = aBitmap->SizeInTwips(); + ASSERT(size.iWidth==0 && size.iHeight==0 || size.iWidth>0 && size.iHeight>0); + // assumption that if we've set the size it is properly formatted + if (size==TSize(0,0)) + { + CWsScreenDevice *const screenDevice = iEikonEnv->ScreenDevice(); + size = aBitmap->SizeInPixels(); + size.iWidth = screenDevice->HorizontalTwipsToPixels(size.iWidth); + size.iHeight = screenDevice->VerticalTwipsToPixels(size.iHeight); + aBitmap->SetSizeInTwips(size); + } + } + +void CVideoAppView::Clear(TBool aClearFull, TDrawNow aDrawNow) + { + // if we have a bitmap buffer clear that. Otherwise clear the whole screen depending + // on aClearFull + if (iBmGc) + { + iBmGc->Reset(); + iBmGc->SetPenStyle(CGraphicsContext::ENullPen); + iBmGc->SetBrushStyle(CGraphicsContext::ESolidBrush); + iBmGc->SetBrushColor(iBackgroundColor); + iBmGc->Clear(); + } + if (aDrawNow!=ENoDrawNow) + { + if (aClearFull) + DrawNow(); + else + { + ActivateGc(); + CWindowGc& gc = SystemGc(); + RWindow& window = Window(); + window.Invalidate(iBmRect); + window.BeginRedraw(iBmRect); + gc.SetPenStyle(CGraphicsContext::ENullPen); + gc.SetBrushStyle(CGraphicsContext::ESolidBrush); + gc.SetBrushColor(iBackgroundColor); + gc.Clear(); + window.EndRedraw(); + DeactivateGc(); + } + } + } + + +void CVideoAppView::MoveBy(const TPoint& aRelMove, TDrawNow aDrawNow) + { + iBmRect.Move(aRelMove); + + if (aDrawNow!=ENoDrawNow) + DrawNow(); + } + +void CVideoAppView::Center(TDrawNow aDrawNow) + { + ASSERT(iBitmapValid && iBmRect.Size() == iBmBuffer->SizeInPixels()); // should only be called when size setup properly + +#ifdef CENTRE_IMAGE + const TPoint center = Rect().Center(); + const TSize bitmapSize = iBmRect.Size(); + const TPoint requiredTl (center.iX-bitmapSize.iWidth/2, center.iY-bitmapSize.iHeight/2); + const TRect newRect(requiredTl, bitmapSize); + iBmRect = newRect; +#endif + + ASSERT(iBitmapValid && iBmRect.Size() == iBmBuffer->SizeInPixels()); // checked worked + + if (aDrawNow!=ENoDrawNow) + DrawNow(); + } + +TBool CVideoAppView::SetBackgroundColor(const TRgb& aColor, TDrawNow aDrawNow) + { + TBool changed = iBackgroundColor!=aColor; + + iBackgroundColor = aColor; + + if (aDrawNow!=ENoDrawNow) + DrawNow(); + + return changed; + } + +void CVideoAppView::SetDisplayModeL(TDisplayMode aDisplayMode, CWsBitmap* aFrame, TDrawNow aDrawNow) + { + + TBool change=aDisplayMode!=iDisplayMode; + + iDisplayMode = aDisplayMode; + + if (iBitmapValid && change) + { + ASSERT(iBmBuffer->Handle()); + + // temp buffer becomes copy of original + CFbsBitmap* tempBuffer = new (ELeave) CWsBitmap(iCoeEnv->WsSession()); + CleanupStack::PushL(tempBuffer); + User::LeaveIfError(tempBuffer->Duplicate(iBmBuffer->Handle())); + + ASSERT(iBmRect.Size()==iBmBuffer->SizeInPixels()); // should be the same + ResizeBufferL(iBmBuffer->SizeInPixels(), iDisplayMode); + // change bitmap + + // bitblt original back + iBmGc->BitBlt(TPoint(0,0), tempBuffer); + CleanupStack::PopAndDestroy(); // tempBuffer + + aFrame->Reset(); // reset the frame + aFrame->Duplicate(iBmBuffer->Handle()); // duplicate the aFrame bitmap handle + } + + Window().SetRequiredDisplayMode(iDisplayMode); + + if (aDrawNow!=ENoDrawNow) + DrawNow(); + } + +// +// CVideoDisplayModeDialog +// + +// list of supported display modes (it matches r_video_display_mode_array in TImageViewer.rss) + +const TDisplayMode KDispMode[] = { EGray2, EGray4, EGray16, EGray256, EColor16, EColor256, EColor4K, EColor64K, EColor16M, EColor16MU, EColor16MA, EColor16MAP }; +const TInt KNumDispMode = sizeof(KDispMode) / sizeof(KDispMode[0]); + +CVideoDisplayModeDialog::CVideoDisplayModeDialog(TDisplayMode& aDisplayMode,TBool& aUseNativeDisplayMode): + iDisplayMode(aDisplayMode), iUseNativeDisplayMode(aUseNativeDisplayMode) + {} + +void CVideoDisplayModeDialog::PreLayoutDynInitL() + { + TInt choice = -1; + + for (TInt index=0; index=0); // should always match something + SetChoiceListCurrentItem(EVideoIdDisplayMode,choice); + } + +TBool CVideoDisplayModeDialog::OkToExitL(TInt /*aButtonId*/) + { + const TInt chosenIndex = ChoiceListCurrentItem(EVideoIdDisplayMode); + ASSERT(chosenIndex& aEncodeOperations,TBool& aCreateThumbnail,TBool& aSaveAsEXIF): + CEikFileSaveAsDialog(aFileName), + iSaveInfo(aSaveInfo), + iEncodeOperations(aEncodeOperations), + iCreateThumbnail(&aCreateThumbnail), + iSaveAsEXIF(&aSaveAsEXIF) + {} + +void CVideoSaveAsDialog::PreLayoutDynInitL() + { + SetTypeL(); + SetCheckBoxState(EVideoIdCreateThumbnailChbx, *iCreateThumbnail ? CEikButtonBase::ESet : CEikButtonBase::EClear); + SetCheckBoxState(EVideoIdSaveAsEXIFChbx, *iSaveAsEXIF ? CEikButtonBase::ESet : CEikButtonBase::EClear); + + CEikFileSaveAsDialog::PreLayoutDynInitL(); + } + +void CVideoSaveAsDialog::SetTypeL() + { + const TUid imageType = iSaveInfo.iImageTypeUid; + + if(imageType == KImageTypeBMPUid) + SetLabelL(EVideoIdSaveAsFormat,R_VIDEO_FILE_FORMAT_BMP); + else if(imageType == KImageTypeGIFUid) + SetLabelL(EVideoIdSaveAsFormat,R_VIDEO_FILE_FORMAT_GIF); + else if(imageType == KImageTypeJPGUid) + { + if ( *iSaveAsEXIF ) + { + SetLabelL(EVideoIdSaveAsFormat,R_VIDEO_FILE_FORMAT_EXIF); + } + else + { + SetLabelL(EVideoIdSaveAsFormat,R_VIDEO_FILE_FORMAT_JPEG); + } + } + else if(imageType == KImageTypeMBMUid) + SetLabelL(EVideoIdSaveAsFormat,R_VIDEO_FILE_FORMAT_MBM); + else if(imageType == KImageTypePNGUid) + SetLabelL(EVideoIdSaveAsFormat,R_VIDEO_FILE_FORMAT_PNG); + else + SetLabelL(EVideoIdSaveAsFormat,R_VIDEO_FILE_FORMAT_CUSTOM); + + } + +void CVideoSaveAsDialog::HandleControlStateChangeL(TInt aControlId) + { + if (aControlId == EVideoIdSaveAsEXIFChbx) + { + *iSaveAsEXIF = CheckBoxState(EVideoIdSaveAsEXIFChbx) == CEikButtonBase::ESet ? ETrue : EFalse; + SetTypeL(); + } + } + +TBool CVideoSaveAsDialog::OkToExitL(TInt aButtonId) + { + if (aButtonId == EVideoIdSaveAsFormat) + { + CEikDialog* dialog = new(ELeave) CVideoFormatDialog(iSaveInfo); + if (dialog->ExecuteLD(R_VIDEO_FILE_FORMAT_DIALOG)) + SetTypeL(); + + return EFalse; + } + else if (aButtonId == EVideoIdEncodeOperations) + { + CEikDialog* dialog = new(ELeave) CExtensionOptionsDialog(iEncodeOperations); + dialog->ExecuteLD(R_VIDEO_ENCODER_EXTENSION_DIALOG); + return EFalse; + } + else if (aButtonId == EEikBidOk) + { + *iCreateThumbnail = CheckBoxState(EVideoIdCreateThumbnailChbx) == CEikButtonBase::ESet ? ETrue : EFalse; + *iSaveAsEXIF = CheckBoxState(EVideoIdSaveAsEXIFChbx) == CEikButtonBase::ESet ? ETrue : EFalse; + } + + return CEikFileSaveAsDialog::OkToExitL(aButtonId); + } + +SEikControlInfo CVideoSaveAsDialog::CreateCustomControlL(TInt /*aControlType*/) + { + /* never called */ + SEikControlInfo info; + info.iTrailerTextId = 0; + info.iFlags = 0; + info.iControl = new (ELeave) CEikTextListBox; + return info; + } +// +// CVideoFormatDialog +// + +CVideoFormatDialog::CVideoFormatDialog(TFileSaveInfo& aSaveInfo): + iSaveInfo(aSaveInfo) + {} + +void CVideoFormatDialog::PreLayoutDynInitL() + { + CEikChoiceList* formatList = STATIC_CAST(CEikChoiceList*,Control(EVideoIdFileFormatType)); + + //Add the available encoders to the dialog + iEncoderList = CPluginInfoArray::NewL(); + formatList->SetArrayL(iEncoderList); //ownership of iEncoderList passed to dialog + + const TInt noOfEncoders = iEncoderList->MdcaCount(); + if(noOfEncoders == 0) + User::Leave(KErrNotFound); + + //Find the index for the selected encoder (via ImageTypeUid) + //if it is not found use the first + TInt index; + for(index=noOfEncoders-1; index > 0; index--) + { + if(iEncoderList->ImageType(index) == iSaveInfo.iImageTypeUid) + break; + } + iSaveInfo.iImageTypeUid = iEncoderList->ImageType(index); + + SetChoiceListCurrentItem(EVideoIdFileFormatType,index); + SetChoiceListCurrentItem(EVideoIdFileFormatBpp,iSaveInfo.iBpp); + SetChoiceListCurrentItem(EVideoIdFileFormatColor,iSaveInfo.iColor); + SetNumberEditorValue(EVideoIdFileFormatFactor,iSaveInfo.iQualityFactor); + SetChoiceListCurrentItem(EVideoIdFileFormatSampling,iSaveInfo.iSampling); + SetChoiceListCurrentItem(EVideoIdFileFormatCompression,iSaveInfo.iCompression); + + ValidateControlState(); + } + +void CVideoFormatDialog::HandleControlStateChangeL(TInt /*aControlId*/) + { + ValidateControlState(); + } + +void CVideoFormatDialog::ValidateControlState() + { + TInt type = ChoiceListCurrentItem(EVideoIdFileFormatType); + TInt bpp = ChoiceListCurrentItem(EVideoIdFileFormatBpp); + TInt color = ChoiceListCurrentItem(EVideoIdFileFormatColor); + TInt compression = ChoiceListCurrentItem(EVideoIdFileFormatCompression); + + TBool bppVisible = ETrue; + TBool colorVisible = ETrue; + TBool factorVisible = EFalse; + TBool samplingVisible = EFalse; + TBool compressionVisible = EFalse; + + + const TUid imageType = iEncoderList->ImageType(type); + + if(imageType == KImageTypeBMPUid) + { + colorVisible = EFalse; + if (bpp == 1) + bpp = 2; + else if ((bpp > 3) && (bpp < 6)) + bpp = 6; + else if (bpp > 6) + bpp = 0; + } + else if(imageType == KImageTypeGIFUid) + { + bppVisible = EFalse; + colorVisible = EFalse; + } + else if(imageType == KImageTypeJPGUid) + { + bppVisible = EFalse; + factorVisible = ETrue; + if (color) + samplingVisible = ETrue; + } + else if(imageType == KImageTypeMBMUid) + { + if (color == 0) + { + if (bpp > 3) + bpp = 0; + } + else + { + if (bpp < 2) + bpp = 2; + } + } + else if(imageType == KImageTypePNGUid) + { + if ((bpp > 3) && (bpp < 6)) + bpp = 6; + else if (bpp > 6) + bpp = 0; + compressionVisible = ETrue; + } + else //Custom encoder + { + bppVisible = EFalse; + colorVisible = EFalse; + } + + SetChoiceListCurrentItem(EVideoIdFileFormatBpp,bpp); + SetChoiceListCurrentItem(EVideoIdFileFormatColor,color); + SetChoiceListCurrentItem(EVideoIdFileFormatCompression,compression); + + MakeLineVisible(EVideoIdFileFormatBpp,bppVisible); + MakeLineVisible(EVideoIdFileFormatColor,colorVisible); + MakeLineVisible(EVideoIdFileFormatFactor,factorVisible); + MakeLineVisible(EVideoIdFileFormatSampling,samplingVisible); + MakeLineVisible(EVideoIdFileFormatCompression,compressionVisible); + } + +TBool CVideoFormatDialog::OkToExitL(TInt /*aButtonId*/) + { + TInt type = ChoiceListCurrentItem(EVideoIdFileFormatType); + iSaveInfo.iImageTypeUid = iEncoderList->ImageType(type); + iSaveInfo.iBpp = ChoiceListCurrentItem(EVideoIdFileFormatBpp); + iSaveInfo.iColor = ChoiceListCurrentItem(EVideoIdFileFormatColor); + iSaveInfo.iQualityFactor = NumberEditorValue(EVideoIdFileFormatFactor); + iSaveInfo.iSampling = ChoiceListCurrentItem(EVideoIdFileFormatSampling); + iSaveInfo.iCompression = ChoiceListCurrentItem(EVideoIdFileFormatCompression); + + return ETrue; + } + +CDecoderOptionsDialog::CDecoderOptionsDialog(TUint& aOptions):iOptions(aOptions) + { + } + + // from CEikDialog +void CDecoderOptionsDialog::PreLayoutDynInitL() + { + SetCheckBoxState(EVideoIdUseThreadForDecoder, iOptions&CImageDecoder::EOptionAlwaysThread ? CEikButtonBase::ESet : CEikButtonBase::EClear); + SetCheckBoxState(EVideoIdDecoderDisableDithering, iOptions&CImageDecoder::EOptionNoDither ? CEikButtonBase::ESet : CEikButtonBase::EClear); + SetCheckBoxState(EVideoIdDecoderAutogenMask, iOptions&CImageDecoder::EAllowGeneratedMask ? CEikButtonBase::ESet : CEikButtonBase::EClear); + SetCheckBoxState(EVideoIdDecodeHighSpeedDecode, iOptions&CImageDecoder::EPreferFastDecode ? CEikButtonBase::ESet : CEikButtonBase::EClear); + SetCheckBoxState(EVideoIdAutoRotateDecode, iOptions&CImageDecoder::EOptionAutoRotate ? CEikButtonBase::ESet : CEikButtonBase::EClear); + } + +TBool CDecoderOptionsDialog::OkToExitL(TInt /*aButtonId*/) + { + iOptions = CheckBoxState(EVideoIdUseThreadForDecoder) == CEikButtonBase::ESet ? CImageDecoder::EOptionAlwaysThread : 0; + iOptions|= CheckBoxState(EVideoIdDecoderDisableDithering) == CEikButtonBase::ESet ? CImageDecoder::EOptionNoDither : 0; + iOptions|= CheckBoxState(EVideoIdDecoderAutogenMask) == CEikButtonBase::ESet ? CImageDecoder::EAllowGeneratedMask : 0; + iOptions|= CheckBoxState(EVideoIdDecodeHighSpeedDecode) == CEikButtonBase::ESet ? CImageDecoder::EPreferFastDecode : 0; + iOptions|= CheckBoxState(EVideoIdAutoRotateDecode) == CEikButtonBase::ESet ? CImageDecoder::EOptionAutoRotate : 0; + + return ETrue; + } + +CExtensionOptionsDialog::CExtensionOptionsDialog(TRect& aClippingRect, + RArray& aOperations, + TInt& aScalingCoefficient, + TImageConvScaler::TScalerQuality& aScalingQuality, + TBool& aLockAspectRatio) + : iClippingRect(&aClippingRect), iOperations(aOperations), iScalingCoefficient(&aScalingCoefficient), + iScalingQuality(&aScalingQuality), iLockAspectRatio(&aLockAspectRatio) + { + iSelectedOperations = new (ELeave) CDesCArrayFlat(20); + } + +CExtensionOptionsDialog::CExtensionOptionsDialog(RArray& aOperations) + : iOperations(aOperations) + { + iSelectedOperations = new (ELeave) CDesCArrayFlat(20); + iOperationOnly = ETrue; + } + +void CExtensionOptionsDialog::PageChangedL(TInt /*aPageId*/) + { + // enable/disable add and clear buttons which are only enabled on Operation Page +// The lines below panic on teh Control call. Looks like a dialog button is not a control +// Control(EVideoIdAdd)->SetDimmed(aPageId != EDecoderExtensionOperationPage); +// Control(EVideoIdClear)->SetDimmed(aPageId != EDecoderExtensionOperationPage); + } + + // from CEikDialog +void CExtensionOptionsDialog::PreLayoutDynInitL() + { + if ( !iOperationOnly ) + { + // crop rect number edits + static_cast(Control(EVideoIdCropTopLeftX))->SetNumber(iClippingRect->iTl.iX); + static_cast(Control(EVideoIdCropTopLeftY))->SetNumber(iClippingRect->iTl.iY); + static_cast(Control(EVideoIdCropWidth))->SetNumber(iClippingRect->Width()); + static_cast(Control(EVideoIdCropHeight))->SetNumber(iClippingRect->Height()); + + /* scaling + coefficient number edit + quality choicelist + aspectratio checkbox + */ + static_cast(Control(EVideoIdScaleCoeff))->SetNumber(*iScalingCoefficient); + static_cast(Control(EVideoIdScaleQuality))->SetCurrentItem(*iScalingQuality); + SetCheckBoxState(EVideoIdScalePreserveAspect, *iLockAspectRatio ? CEikButtonBase::ESet : CEikButtonBase::EClear); + } + + /* operations + fill selected operations + */ + CEikTextListBox* selectOpsListBox = static_cast(Control(EVideoIdSelectedOperations)); + + selectOpsListBox->CreateScrollBarFrameL(); + selectOpsListBox->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff, CEikScrollBarFrame::EOn); + + operationName[0] = _L("0x01 | ERotation90DegreesClockwise"); + operationName[1] = _L("0x02 | ERotation180DegreesClockwise"); + operationName[2] = _L("0x04 | ERotation270DegreesClockwise"); + operationName[3] = _L("0x08 | EMirrorHorizontalAxis"); + operationName[4] = _L("0x10 | EMirrorVerticalAxis"); + + for (TInt i = 0; i < iOperations.Count(); i++) + { + if ( iOperations[i] > 0 ) + { + TInt temp = iOperations[i]; + TInt shiftCount = 0; + while ( temp ) + { + temp = temp >> 1; + ++shiftCount; + } + iSelectedOperations->AppendL(operationName[shiftCount-1]); + } + } + + selectOpsListBox->Model()->SetItemTextArray(iSelectedOperations); + selectOpsListBox->Model()->SetOwnershipType(ELbmDoesNotOwnItemArray); + + } + +// DEF115967: Panic while editing Setup extensions Value +void CExtensionOptionsDialog::PrepareForFocusTransitionL() + { + // The dialog will check for blank input in the control that + // has been edited. If it is blank the value 9999...9 will be + // placed there to ensure control->Number() returns something. + // There appears to be no way of getting a different value put + // in a blank control (IsBlank function is protected). + + CEikDialog::PrepareForFocusTransitionL(); + } + + +SEikControlInfo CExtensionOptionsDialog::CreateCustomControlL(TInt /*aControlType*/) + { + /* never called */ + SEikControlInfo info; + info.iTrailerTextId = 0; + info.iFlags = 0; + info.iControl = new (ELeave) CEikTextListBox; + return info; + } + +TBool CExtensionOptionsDialog::OkToExitL(TInt aButtonId) + { + TBool exit = EFalse; + + switch ( aButtonId ) + { + case EEikBidOk: + { + if ( !iOperationOnly ) + { + // get crop rect + iClippingRect->iTl.iX = static_cast(Control(EVideoIdCropTopLeftX))->Number(); + iClippingRect->iTl.iY = static_cast(Control(EVideoIdCropTopLeftY))->Number(); + iClippingRect->SetWidth(static_cast(Control(EVideoIdCropWidth))->Number()); + iClippingRect->SetHeight(static_cast(Control(EVideoIdCropHeight))->Number()); + + // get scaling + *iScalingCoefficient = static_cast(Control(EVideoIdScaleCoeff))->Number(); + *iScalingQuality = static_cast + (static_cast(Control(EVideoIdScaleQuality))->CurrentItem()); + *iLockAspectRatio = (CheckBoxState(EVideoIdScalePreserveAspect) == CEikButtonBase::ESet) ? ETrue : EFalse; + } + + // get operations + CTextListBoxModel * selectOpsModel = static_cast(Control(EVideoIdSelectedOperations))->Model(); + iOperations.Reset(); + for (TInt i = 0; i < selectOpsModel->NumberOfItems(); i++) + { + TLex enumLex(selectOpsModel->ItemText(i).Mid(2,2)); // Hex value of enum + TUint operation = 0; + enumLex.Val(operation,EHex); + iOperations.Append(operation); + } + } + // deliberate fall through + case EEikBidCancel: + { + // iOperations fill up from iSeletedOperations + delete iSelectedOperations; + exit = ETrue; + } + break; + + case EVideoIdAdd: + { + TInt currentItem = static_cast(Control(EVideoIdOperations))->CurrentItem(); + iSelectedOperations->AppendL(operationName[currentItem]); + CEikTextListBox* selectOpsListBox = static_cast(Control(EVideoIdSelectedOperations)); + selectOpsListBox->Model()->SetItemTextArray(iSelectedOperations); + selectOpsListBox->HandleItemAdditionL(); + } + break; + + case EVideoIdClear: + { + iSelectedOperations->Reset(); + CEikTextListBox* selectOpsListBox = static_cast(Control(EVideoIdSelectedOperations)); + selectOpsListBox->Model()->SetItemTextArray(iSelectedOperations); + selectOpsListBox->HandleItemAdditionL(); + } + break; + + default: + break; + } + + return exit; + } + +// +// CVideoWalker implementation +// + +CVideoWalker* CVideoWalker::NewL(CVideoAppUi* aAppUi) + { + CVideoWalker* result = new (ELeave) CVideoWalker(aAppUi); + return result; + } + +CVideoWalker::CVideoWalker(CVideoAppUi* aAppUi): + CActive(CActive::EPriorityStandard), + iAppUi(aAppUi) + { + CActiveScheduler::Add(this); + } + +CVideoWalker::~CVideoWalker() + { + Cancel(); + } + +// used when we need to pass status variable - simultaneously calls SetActive +TRequestStatus& CVideoWalker::ActiveStatus() + { + SetActive(); + return iStatus; + } + +// for completion ASAP on this +void CVideoWalker::SelfComplete(TInt aError) + { + TRequestStatus* status = &ActiveStatus(); + User::RequestComplete(status, aError); + } + +// calls AppUi->RunL() which is expected to handle the call +void CVideoWalker::RunL() + { + iAppUi->RunL(this, iStatus.Int()); + } + +// calls AppUi->DoCancel() which is expected to handle the call +void CVideoWalker::DoCancel() + { + iAppUi->DoCancel(this); + } + +// +// CVideoDocument +// + +CVideoDocument::CVideoDocument(CEikApplication& aApp) + : CEikDocument(aApp) + { + } + +CEikAppUi* CVideoDocument::CreateAppUiL() + { + return new(ELeave) CVideoAppUi; + } + +// +// CVideoApp +// + +TUid CVideoApp::AppDllUid() const + { + return KUidTVideo; + } + +CApaDocument* CVideoApp::CreateDocumentL() + { + return new(ELeave) CVideoDocument(*this); + } + + +// +// Base factory function +// + +#include +LOCAL_C CApaApplication* NewApplication() + { + return new CVideoApp; + } + +// +// EXE Entry point +// + +GLDEF_C TInt E32Main() + { + return EikStart::RunApplication(NewApplication); + } +