--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/imaging/imagingfws/ImageDisplay/plugins/IclWrapper/GenericIclWrapper.cpp Wed Aug 25 12:29:52 2010 +0300
@@ -0,0 +1,714 @@
+// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+
+#include "GenericIclWrapper.h"
+#include <icl/imagedisplaypaniccodes.h>
+#include "MiscUtils.h"
+
+#include "ExifImageDisplayPanic.h"
+
+#define KZeroDelay TTimeIntervalMicroSeconds(0)
+_LIT(KGenIclWrapperPanicCategory, "GenIclWrapperImgDisplay");
+
+CGenericImageDisplayPlugin* CGenericImageDisplayPlugin::NewL()
+ {
+ CGenericImageDisplayPlugin* self = new(ELeave) CGenericImageDisplayPlugin(KGenIclWrapperPanicCategory);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+void CGenericImageDisplayPlugin::ConstructL()
+ {
+ User::LeaveIfError( iFs.Connect() );
+ iPlayer = new (ELeave) CImagePlayer(*this);
+ iDelayedCb = CDelayedCallback::NewL(*this);
+ }
+
+CGenericImageDisplayPlugin::~CGenericImageDisplayPlugin()
+ {
+ if (iTransformer != NULL)
+ {
+ iTransformer->Cancel();
+ delete iTransformer;
+ }
+ if (iMaskTransformer != NULL)
+ {
+ iMaskTransformer->Cancel();
+ delete iMaskTransformer;
+ }
+
+ delete iDelayedCb;
+ delete iPlayer;
+ delete iDecoder;
+ iFs.Close();
+ }
+
+CGenericImageDisplayPlugin::CGenericImageDisplayPlugin(const TDesC& aPanicCategoryStr):
+ iPanicCategory(aPanicCategoryStr),
+ iMaxReductionFactor(KMaxReductionFactor),
+ iMaxUnscaledSize(KMaxTInt,KMaxTInt),
+ iExtHandler(*this),
+ iScaleQuality(-1),
+ iPluginImgStatus(CImageDisplay::EImageTypeUnknown)
+ {
+ }
+
+void CGenericImageDisplayPlugin::Panic(TInt aPanicNumber) const
+ {
+ User::Panic(iPanicCategory, aPanicNumber);
+ }
+
+void CGenericImageDisplayPlugin::OpenL()
+ {
+ iValidBitmap = EFalse;
+ const TUint option=(Options() & (CImageDisplay::EOptionThumbnail|CImageDisplay::EOptionMainImage));
+ if (option==CImageDisplay::EOptionsUndefined ||
+ option == (CImageDisplay::EOptionThumbnail|CImageDisplay::EOptionMainImage))
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ switch ( SourceType() )
+ {
+ case CImageDisplayPlugin::EImgSrcFileName:
+ {
+
+ TMMFileSource src(SourceFilename(), SourceDataId(), SourceDataIntent());
+ iDecoder = CImageDecoder::FileNewL(iFs, src, CImageDecoder::EAllowGeneratedMask, KNullUid, KNullUid, RequiredImageClass());
+ }
+ break;
+
+ case CImageDisplayPlugin::EImgSrcFileHandle:
+ {
+ TMMFileHandleSource src(SourceFileHandle(), SourceDataId(), SourceDataIntent());
+ iDecoder = CImageDecoder::FileNewL(iFs, src, CImageDecoder::EAllowGeneratedMask, KNullUid, KNullUid, RequiredImageClass());
+ }
+ break;
+
+ case CImageDisplayPlugin::EImgSrcDescriptor:
+ iDecoder = CImageDecoder::DataNewL(iFs, SourceData(), CImageDecoder::EAllowGeneratedMask, KNullUid, KNullUid, RequiredImageClass());
+ break;
+
+ default:
+ ASSERT(EFalse);
+ User::Leave(KErrArgument);
+ }
+ iValidBitmap = EFalse;
+ iImageIsThumbnail = (option==CImageDisplay::EOptionThumbnail);
+
+ if (iImageIsThumbnail)
+ {
+ iDecoder->SetImageTypeL(CImageDecoder::EImageTypeThumbnail ); // leaves if there is no thumbnail
+ }
+
+ AfterOpenL(); // allow derived plug-in to perform some initialization
+ iRotationOptions = EffectiveRotation();
+ FillRecommendedSizesL();
+ CacheImageStatus();
+ }
+
+void CGenericImageDisplayPlugin::Play()
+ {
+ iIsPaused = EFalse;
+ if (iCallBackIsPending)
+ {
+ iDelayedCb->CallAfter(KZeroDelay);
+ iCallBackIsPending = EFalse;
+ return;
+ }
+ if (IsStatusSet(EStatusNoMoreToDecode))
+ {
+ ASSERT(IsStatusSet(EStatusPaused)==EFalse);
+ if (iState < EInitCompleted)
+ {
+ Panic(EPanicNotInitialized);
+ }
+ if (iValidBitmap && iLastError==KErrNone)
+ {
+ ClearStatusFlag(EStatusPaused|EStatusBusy);
+ iDelayedCb->CallAfter(KZeroDelay);
+ return;
+ }
+ ClearStatusFlag(EStatusNoMoreToDecode);
+ iState = EInitCompleted;
+ }
+ else if (IsStatusSet(EStatusPaused)==EFalse && iState>=EInitCompleted)
+ {
+ if (iState==EInitCompleted && IsStatusSet(EStatusBusy)==EFalse)
+ {
+ iPlayer->Play(*iDecoder, EffectiveDispMode(), (iImageIsThumbnail? 1 : CImagePlayer::KNoFrameLimit) );
+ iState = EProcessing;
+ }
+ return;
+ }
+
+ ClearStatusFlag(EStatusPaused|EStatusNoMoreToDecode|EStatusBusy);
+ switch (iState)
+ {
+ case EIdle:
+ TRAPD(err,
+ CompleteInitL();
+ );
+ iOutputRect=TRect(0,0,DestinationSizeInPixels().iWidth, DestinationSizeInPixels().iHeight);
+ if (err != KErrNone)
+ {
+ AsyncCallbackImageReady(NULL, EStatusNoMoreToDecode, iOutputRect, err);
+ iState = EInitFailed;
+ return;
+ }
+ iPlayer->Play(*iDecoder, EffectiveDispMode(), (iImageIsThumbnail? 1 : CImagePlayer::KNoFrameLimit) );
+ iState = EProcessing;
+ break;
+
+ case EInitFailed:
+ Panic(EPanicInitFailed);
+ break;
+
+ case EInitCompleted:
+ case EProcessing:
+ iPlayer->Resume();
+ iState = EProcessing;
+ break;
+
+ case ETransforming:
+ iTransformer->Restart();
+ break;
+
+ case ETransformingMask:
+ iMaskTransformer->Restart();
+ break;
+
+ default:
+ ASSERT(EFalse);
+ }
+
+ SetStatusFlag(EStatusBusy);
+ }
+
+void CGenericImageDisplayPlugin::Pause()
+ {
+ if (iIsPaused)
+ {
+ return;
+ }
+ if ( CallbackIsRunning() )
+ {
+ CancelCallback();
+ // actually the framework may not be able to cancel the callback
+ // if the execution point has already passed to the client code and it yielded to AS somehow
+ // so we check if the callback was actually cancelled by trying it after cancel attempt
+ iCallBackIsPending = !CallbackIsRunning();
+ }
+ else
+ {
+ if (iTransformer != NULL && iState == ETransforming)
+ {
+ iTransformer->Cancel();
+ }
+ else if (iMaskTransformer != NULL && iState == ETransformingMask)
+ {
+ iMaskTransformer->Cancel();
+ }
+ else
+ {
+ iPlayer->Pause();
+ }
+ if (!IsStatusSet(EStatusNoMoreToDecode))
+ {
+ SetStatusFlag(EStatusPaused);
+ iIsPaused = ETrue;
+ }
+ }
+ ClearStatusFlag(EStatusBusy);
+ }
+
+void CGenericImageDisplayPlugin::StopPlay()
+ {
+ CancelCallback();
+ iNextFrameDelay = 0;
+ iIsPaused = EFalse;
+ iValidBitmap = EFalse;
+ iCallBackIsPending = EFalse;
+ if (iState >= EInitCompleted)
+ {
+ iState = EInitCompleted;
+ }
+ if (iTransformer != NULL)
+ {
+ iTransformer->Cancel();
+ }
+ if (iMaskTransformer != NULL)
+ {
+ iMaskTransformer->Cancel();
+ }
+ if (iPlayer != NULL)
+ {
+ iPlayer->Cancel();
+ }
+ if (iDelayedCb != NULL)
+ {
+ iDelayedCb->Cancel();
+ }
+ ClearStatusFlag(EStatusBusy|EStatusPaused);
+ }
+
+void CGenericImageDisplayPlugin::GetBitmap(const CFbsBitmap*& aBitmap, const CFbsBitmap*& aMask) const
+ {
+ if (iState < EInitCompleted)
+ {
+ Panic(EPanicNotInitialized);
+ }
+ if (ValidBitmap())
+ {
+ aBitmap = iCurrentFrame;
+ aMask = iCurrentMask;
+ }
+ else
+ {
+ aBitmap = NULL;
+ aMask = NULL;
+ }
+ }
+
+const CImageDisplay::RImageSizeArray& CGenericImageDisplayPlugin::RecommendedImageSizes() const
+ {
+ return iImageSizes;
+ }
+
+TInt CGenericImageDisplayPlugin::NumFrames(TInt& aNumFrames) const
+ {
+ if (iDecoder->IsImageHeaderProcessingComplete())
+ {
+ aNumFrames = iDecoder->FrameCount();
+ return KErrNone;
+ }
+ aNumFrames = -1;
+ return KErrNotReady;
+ }
+
+TUint CGenericImageDisplayPlugin::ImageStatus() const
+ {
+ return iPluginImgStatus;
+ }
+
+TBool CGenericImageDisplayPlugin::ValidBitmap() const
+ {
+ return iValidBitmap;
+ }
+
+void CGenericImageDisplayPlugin::CacheImageStatus()
+ {
+ TInt numFrames;
+ iPluginImgStatus=(NumFrames(numFrames)==KErrNone && numFrames > 1)? CImageDisplay::EImageMultiFrame : CImageDisplay::EImageSingleFrame;
+ for (TInt i=0; i<numFrames; ++i)
+ {
+ if (iDecoder->FrameInfo(i).iDelay.Int64() != 0)
+ {
+ iPluginImgStatus|= CImageDisplay::EImageAnimated;
+ if (iImageHasFloatingSubImgs)
+ {
+ break;
+ }
+ }
+ if (iDecoder->FrameInfo(i).iFrameCoordsInPixels != iDecoder->FrameInfo(0).iFrameCoordsInPixels)
+ {
+ iImageHasFloatingSubImgs = ETrue;
+ if (iPluginImgStatus & CImageDisplay::EImageAnimated)
+ {
+ break;
+ }
+ }
+ }
+ iPluginImgStatus|=((iDecoder->FrameInfo().iFlags&TFrameInfo::ETransparencyPossible) ? CImageDisplay::EImageMasked : 0);
+ iPluginImgStatus|=(ThumbnailExists()?CImageDisplay::EImageHasThumbnail : 0);
+ iPluginImgStatus|=((iDecoder->FrameInfo().iFlags&TFrameInfo::EFullyScaleable)?CImageDisplay::EImageIsFullyScalable : 0);
+ }
+
+void CGenericImageDisplayPlugin::OnPlayEvent(TInt aErrorCode, TUint aEventFlags, CFbsBitmap* aFrame, CFbsBitmap* aMask)
+ {
+ ASSERT(IsStatusSet(EStatusPaused)==EFalse);
+ iLastError = aErrorCode;
+ if (aErrorCode == KErrNone)
+ {
+ iValidBitmap = EFalse;
+ iPluginStatus = aEventFlags;
+ iCurrentMask = aMask;
+ if (iTransformer != NULL )
+ {
+ SetStatusFlag(EStatusBusy);
+ iState = ETransforming;
+ iTransformer->Singleton().SetTrueSrcSize( iPlayer->OriginalFrameSize() );
+ iTransformer->Transform(aFrame, MaintainAspectRatio());
+ }
+ else
+ {
+ iValidBitmap = ETrue;
+ iCurrentFrame = aFrame;
+ ClearStatusFlag(EStatusBusy);
+ if ((aEventFlags&EStatusNoMoreToDecode)==0)
+ {
+ SetStatusFlag(EStatusPaused);
+ }
+ const TTimeIntervalMicroSeconds delay(iNextFrameDelay);
+ iNextFrameDelay = iPlayer->CurrentFrameInfo().iDelay;
+ iDelayedCb->CallAfter(delay);
+ }
+ }
+ else
+ {
+ iState = EInitFailed;
+ iPluginStatus = EStatusNoMoreToDecode;
+ iCurrentFrame = NULL;
+// we've got error, so there is no need to go via delayed callback
+ AsyncCallbackImageReady(iCurrentFrame, iPluginStatus, iOutputRect, aErrorCode);
+ }
+ }
+
+void CGenericImageDisplayPlugin::OnTransformDone(TInt aError)
+ {
+ TTimeIntervalMicroSeconds delay(0);
+ if (aError == KErrNone)
+ {
+ if (iCurrentMask != NULL && iState == ETransforming)
+ {
+ iMaskTransformer->Transform(iCurrentMask, MaintainAspectRatio());
+ iState = ETransformingMask;
+ return;
+ }
+ SetStatusFlag(EStatusFrameReady);
+ if (!IsStatusSet(EStatusNoMoreToDecode))
+ {
+ SetStatusFlag(EStatusPaused);
+ }
+ iTransformer->GetBitmap(iCurrentFrame);
+ if (iCurrentMask)
+ {
+ iMaskTransformer->GetBitmap(iCurrentMask);
+ }
+ if (iCurrentFrame != NULL)
+ {
+ iValidBitmap= ETrue;
+ delay = iNextFrameDelay;
+ }
+ iNextFrameDelay = iPlayer->CurrentFrameInfo().iDelay;
+ iState = EProcessing;
+ }
+ else
+ {
+ iState = EInitFailed;
+ iValidBitmap = EFalse;
+ iCurrentFrame = NULL;
+ SetStatusFlag(EStatusNoMoreToDecode);
+ ClearStatusFlag(EStatusBusy|EStatusPaused);
+ }
+
+ ClearStatusFlag(EStatusBusy);
+ iLastError = aError;
+ iDelayedCb->CallAfter(delay);
+ }
+
+void CGenericImageDisplayPlugin::FillRecommendedSizesL()
+ {
+ ASSERT( iDecoder->IsImageHeaderProcessingComplete() );
+ TRect clipRect;
+ const TBool clipDefined=SourceRect(clipRect);
+ const TFrameInfo& FrameInfo=iDecoder->FrameInfo();
+
+ TSize imageSize(clipDefined? clipRect.Size() : FrameInfo.iFrameCoordsInPixels.Size() );
+ RotateSize(imageSize, iRotationOptions);
+ GenRecommendedSizesL(iImageSizes, imageSize, KMaxReductionFactor);
+ }
+
+void CGenericImageDisplayPlugin::GenRecommendedSizesL(RSizeArray& aArray,const TSize& aOriginalSize,TInt aMaxReduction )
+ {
+ aArray.Reset();
+ TSize reducedSize(aOriginalSize);
+ TInt i=0;
+ do
+ {
+ User::LeaveIfError( aArray.Append(reducedSize) );
+ if (KErrNone != iDecoder->ReducedSize(aOriginalSize, ++i, reducedSize))
+ {
+ break;
+ }
+
+ } while ( i<=aMaxReduction &&
+ reducedSize.iWidth <= MaxUnscaledSize().iWidth && reducedSize.iHeight <= MaxUnscaledSize().iHeight);
+ }
+
+TBool CGenericImageDisplayPlugin::SetupPlayerGetScalingNeeded(const TSize& aImageSize, const TSize& aTrueImgSize)
+ {
+ TSize effectiveDestSize( DestinationSizeInPixels() );
+ RotateSize(effectiveDestSize, iRotationOptions);
+
+ const TSize askSize( effectiveDestSize );
+ // in case of clipping and upscaling - decode to original size, clip then upscale
+ // in case of clipping and downscaling- decode to downscaled, then clip
+ const TSize destSize( aImageSize == aTrueImgSize ? askSize : // no clipping so decode to dest size
+ (IsSize2Exceeds1(aTrueImgSize, askSize)?aTrueImgSize:
+ ScaleSize(effectiveDestSize, aImageSize, aTrueImgSize) )
+ );
+ if ((iDecoder->FrameInfo().iFlags&TFrameInfo::EFullyScaleable))
+ {
+ iPlayer->Setup( destSize, KZeroReductionFactor, KZeroReductionFactor);
+ return EFalse;
+ }
+
+ TBool scalingNeeded=EFalse;
+ TInt neededReduction=iDecoder->ReductionFactor(aTrueImgSize, destSize);
+ TSize reducedSize(-1,-1);
+ // if given reduction factor is not supported we'd go using scaler
+ iDecoder->ReducedSize(aTrueImgSize, neededReduction, reducedSize);
+ // animated images suffer from "1 pixel difference" problems when they are composed of reduced parts
+ // so always use scaling for such images
+ const TBool KNoReductionAllowed=(iImageHasFloatingSubImgs && (iPluginImgStatus & CImageDisplay::EImageAnimated));
+ if (neededReduction>=0 && neededReduction<=KMaxReductionFactor && reducedSize==destSize
+ && !KNoReductionAllowed)
+ {
+ // destination size is achivable through reduction factor
+ TInt maxReduction=(IsSize2Exceeds1(iMaxUnscaledSize,destSize)? Max(iMaxReductionFactor,neededReduction) : neededReduction);
+ iPlayer->Setup(reducedSize, maxReduction ,neededReduction);
+ scalingNeeded=(maxReduction != neededReduction);
+ }
+ else
+ {
+ scalingNeeded=ETrue;
+ if (IsSize2Exceeds1(aTrueImgSize, destSize) || KNoReductionAllowed)// we've got upscaling, or no reduction is allowed
+ {
+ iPlayer->Setup(aTrueImgSize, KZeroReductionFactor, KZeroReductionFactor);
+ }
+ else
+ {
+ // we do not apply reduction for sizes smaller than iMaxUnscaledSize
+ TInt reduction=iDecoder->ReductionFactor(destSize, iMaxUnscaledSize);
+ reduction=Max(0, Min(iMaxReductionFactor, reduction));
+ iPlayer->Setup(aTrueImgSize, reduction, KZeroReductionFactor);
+ // and we have to use further downscaling to achieve final target size
+ }
+ }
+ return scalingNeeded;
+ }
+
+void CGenericImageDisplayPlugin::CompleteInitL()
+ {
+ ASSERT( iDecoder->IsImageHeaderProcessingComplete() );
+ iNumberOfFrames = iDecoder->FrameCount();
+ TBool needsMask=EFalse;
+
+ for (TInt i=0; i<iNumberOfFrames && !needsMask; ++i)
+ {
+ needsMask = ( (iDecoder->FrameInfo(i).iFlags & TFrameInfo::ETransparencyPossible) != 0 );
+ }
+ const TFrameInfo& frameInfo=iDecoder->FrameInfo();
+ TRect frameRect(frameInfo.iFrameCoordsInPixels);
+ const TSize imageSize(frameRect.Size());
+ TRect clipRect;
+ const TBool clipDefined=SourceRect(clipRect);
+ if (!clipDefined)
+ {
+ clipRect=frameRect;
+ }
+ else
+ {
+ TRect clipTest(clipRect);
+ clipTest.Intersection(frameRect);
+ if (clipTest != clipRect ) // clipping rect is outside the image rect
+ {
+ User::Leave( KErrArgument );
+ }
+ }
+
+ TBool scalingNeeded=SetupPlayerGetScalingNeeded( clipDefined?clipRect.Size():imageSize, imageSize);
+
+ if (iRotationOptions || clipDefined || scalingNeeded )
+ {
+ CTransformerSharedData* singleton=CTransformerSharedData::NewL();
+ CleanupReleasePushL(*singleton);
+ singleton->SetTransformOptions(iRotationOptions);
+ singleton->SetTrueSrcSize(imageSize);
+ if (clipDefined)
+ {
+ singleton->SetClipRect(clipRect);
+ }
+ iTransformer= CAsyncTransformer::NewL(*this, *singleton, DestinationSizeInPixels());
+
+ if (needsMask)
+ {
+ iMaskTransformer= CAsyncTransformer::NewL(*this, *singleton, DestinationSizeInPixels());
+ }
+ CleanupStack::PopAndDestroy(singleton);
+
+ if (iScaleQuality!=-1)
+ {
+ User::LeaveIfError( iTransformer->SetScaleQuality(iScaleQuality) );
+ if (iMaskTransformer)
+ {
+ User::LeaveIfError( iMaskTransformer->SetScaleQuality(iScaleQuality) );
+ }
+ }
+ }
+ iState = EInitCompleted;
+ }
+
+TInt CGenericImageDisplayPlugin::ExtensionInterface(TUid aIFaceUid, TAny*& aIFacePtr)
+ {
+ aIFacePtr = NULL;
+ if (aIFaceUid == KUidGenIclImageDisplayPluginExtUid)
+ {
+ aIFacePtr = static_cast<MGenIclImageDisplayExtension*>(&iExtHandler);
+ return KErrNone;
+ }
+ return KErrNotSupported;
+ }
+
+TBool CGenericImageDisplayPlugin::ThumbnailExists() const
+ {
+ return EFalse;
+ }
+
+TUint CGenericImageDisplayPlugin::EffectiveRotation() const
+ {
+ return Options() & ( CImageDisplay::EOptionMirrorVertical |
+ (CImageDisplay::EOptionMirrorVertical - CImageDisplay::EOptionRotateCw90) );
+ }
+
+TInt CGenericImageDisplayPlugin::DoSetScaleQuality(TInt aQualityValue)
+ {
+ iScaleQuality = aQualityValue;
+ TInt err=KErrNone;
+ if (iTransformer != NULL)
+ {
+ err=iTransformer->SetScaleQuality(aQualityValue);
+ }
+ if (err==KErrNone && iMaskTransformer != NULL)
+ {
+ err=iMaskTransformer->SetScaleQuality(aQualityValue);
+ }
+
+ return err;
+ }
+
+TInt CGenericImageDisplayPlugin::DoSetMaximumReductionFactor(TInt aMaxReductionFactor)
+ {
+ if (aMaxReductionFactor<0 || aMaxReductionFactor>KMaxReductionFactor)
+ {
+ return KErrArgument;
+ }
+ iMaxReductionFactor = aMaxReductionFactor;
+ return KErrNone;
+ }
+
+TInt CGenericImageDisplayPlugin::SetMaxUnscaledSize(const TSize& aSize)
+ {
+ if (aSize.iWidth < 1 || aSize.iHeight < 1)
+ {
+ return KErrArgument;
+ }
+ iMaxUnscaledSize = aSize;
+ return KErrNone;
+ }
+
+void CGenericImageDisplayPlugin::AfterOpenL()
+ {
+ }
+
+TUid CGenericImageDisplayPlugin::RequiredImageClass() const
+ {
+ return KNullUid;
+ }
+
+void CGenericImageDisplayPlugin::OnCallback()
+ {
+ if (iIsPaused)
+ {
+ iCallBackIsPending = ETrue;
+ return;
+ }
+ AsyncCallbackImageReady(iCurrentFrame, iPluginStatus, iOutputRect, iLastError);
+ }
+
+/*static*/
+CDelayedCallback* CDelayedCallback::NewL(MCallbackClient& aClient)
+ {
+ CDelayedCallback* self=new (ELeave) CDelayedCallback(aClient);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+void CDelayedCallback::CallAfter(const TTimeIntervalMicroSeconds& aAfter)
+ {
+ TTime now;
+ now.HomeTime();
+ const TInt64 KTimerTreshold =8000; // 8 ms, we don't go trought timer for delays less than that
+ const TInt64 KDelayDelta =4000; // 4 ms, make delay 4 ms less to account time before we reach client
+ const TInt64 requiredDelay = aAfter.Int64() - (now.Int64() - iLatestCallbackAt.Int64());
+ if ( requiredDelay <= KTimerTreshold )
+ {
+ iLatestCallbackAt = now;
+ iClient.OnCallback();
+ }
+ else
+ {
+ CTimer::After( TTimeIntervalMicroSeconds32( I64INT(requiredDelay-KDelayDelta) ) );
+ }
+ }
+
+void CDelayedCallback::Cancel()
+ {
+ CTimer::Cancel();
+ }
+
+void CDelayedCallback::RunL()
+ {
+ iLatestCallbackAt.HomeTime();
+ iClient.OnCallback();
+ }
+
+const TUid TExtTie::Uid() const
+ {
+ return KUidGenIclImageDisplayPluginExtUid;
+ }
+
+void TExtTie::Release()
+ {
+ }
+
+TInt TExtTie::SetScaleQuality(TInt aQualityLevel)
+ {
+ return iImplementor.DoSetScaleQuality(aQualityLevel);
+ }
+
+TInt TExtTie::SetMaximumReductionFactor(TInt aMaxReductionFactor)
+ {
+ return iImplementor.DoSetMaximumReductionFactor(aMaxReductionFactor);
+ }
+
+TInt TExtTie::SetMaximumNonReducedSize(const TSize& aSize)
+ {
+ return iImplementor.SetMaxUnscaledSize(aSize);
+ }
+
+
+