sl@0: // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // Implements CTCrpAnim sl@0: // Test CRP animations & their interaction with overlapping transparent/non-transparent windows sl@0: // & wserv's underlying redraw-store strategies sl@0: // sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: @test sl@0: @internalComponent - Internal Symbian test code sl@0: */ sl@0: sl@0: #include sl@0: #include "tcrpanim.h" sl@0: sl@0: // RUN_SAMPLE_ON_LEFT allows the demo animation to run in the left-hand window during testing. sl@0: // Used for demonstration purposes only sl@0: #define RUN_SAMPLE_ON_LEFT sl@0: sl@0: namespace //anonymous local scope sl@0: { sl@0: const TInt KAnimationFrameDelayTime = 50000; // delay in microseconds between frames sl@0: const TInt KShortDelayLoop = 2*KAnimationFrameDelayTime; // delay time in microseconds used in test cases sl@0: const TInt KAnimationTotalFrames = 40; // total number of frames in a CWsGraphicBitmapAnimation sl@0: const TInt KAnimDimension = 40; // animation width/height. We're enforcing a square animation here sl@0: const TInt KFrameMissedAnimationsThreshold = 10; // maximum number of missed frame steps allowed sl@0: const TInt KAnimationTearWidthThreshold = 4; // maximum columns permitted between a tear sl@0: const TInt KMinGoodFrameThreshold = 30; // percentage threshold for number of good frames detected in a test sl@0: const TInt KMaxXY = 200; // arbitrary maximum size of square used to invalidate a window sl@0: const TInt KMaxRepeatDraw = 2; // arbitrary value for DrawLine calls during a Draw sl@0: TUid KUidTestAnimation2 = {0xBAADF00D}; // unique id. for CWsGraphicBitmapAnimation object sl@0: const TUint32 KWhitePixels = 0xFFFFFFFF; // 32-bit mask value for rgb white sl@0: const TUint32 KBlackPixels = 0x00000000; // 32-bit value for rgb black sl@0: const TPoint KPointZero(0,0); // initial point used for animation creation & manipulation (currently 0,0) sl@0: const TPoint KPointOffsite(1000,1000); // point used to draw off-screen sl@0: const TDisplayMode KTestDisplayMode = EColor16MU; // display mode used for testing sl@0: const TInt KFrameStepCalculation = Max(1, KAnimDimension/Max(1, KAnimationTotalFrames)); // determine framestep size in columns sl@0: sl@0: enum TColorDetected sl@0: { sl@0: ECantTell=0, sl@0: EDetRed=1, sl@0: EDetGreen=2, sl@0: EDetBlue=4, sl@0: EDetBlack=0x10, sl@0: EDetGrey=0x20, sl@0: EDetWhite=0x40 sl@0: }; sl@0: sl@0: class CCrpAnim; sl@0: class CAnimRedrawWindow : public CTWin sl@0: { sl@0: public: sl@0: CAnimRedrawWindow(CCrpAnim *aAnimWindow, TBool aIsBase); sl@0: ~CAnimRedrawWindow(); sl@0: void Draw(); sl@0: private: sl@0: CCrpAnim *iAnimWindow; sl@0: TBool iIsBase; sl@0: }; sl@0: sl@0: class CCrpAnim : public CBase sl@0: { sl@0: friend class CAnimRedrawWindow; sl@0: public: sl@0: enum TWinType sl@0: { sl@0: ERedraw, sl@0: EBlank, // note: not currently used in tcrpanim tests sl@0: EBackedUp // note: not currently used in tcrpanim tests sl@0: }; sl@0: public: sl@0: CCrpAnim(TBool aIsBase, TWinType aWinType); sl@0: ~CCrpAnim(); sl@0: enum sl@0: { sl@0: ENoTransparency=0x100 sl@0: }; sl@0: void ConstructL(const TPoint &aPos, const TSize &aSize,const TInt aAlphaValue=ENoTransparency); sl@0: void DoDraw(TBool aBlankIt); sl@0: inline void DoDraw(); sl@0: void DoDrawEllipse(); sl@0: inline TSize Size() {return iCtWin->Size();}; sl@0: inline RWindowBase* BaseWin() const {return iCtWin->BaseWin();}; sl@0: inline RWindow* Window() const {return STATIC_CAST(RWindow*, iCtWin->BaseWin());}; sl@0: inline CTBaseWin* CtBaseWin() {return iCtWin;}; sl@0: inline void Invalidate() {CTUser::Splat(TheClient, TRect(iCtWin->Position(), iCtWin->Size()), KRgbGray);}; sl@0: void Invalidate(const TRect &aRect); sl@0: static void SetEllipseDrawMode(CGraphicsContext::TDrawMode aEllipseDrawMode); sl@0: void InvalidateAndRedraw(TBool aUseBlankItMember,TBool aBlankIt,TBool aUseRWindowInvalidate,TRect* aRect=NULL); sl@0: sl@0: //A bit of an animation interface... sl@0: //I have written this interface to be amenable to playing multiple animations, sl@0: //which I think needs testing, sl@0: //but the underlying implementation assumes one animation at present. sl@0: //Your mission, should you choose to accept it, .... sl@0: sl@0: void SetPosAnimation(const TUid& aUid, const TRect& aRect); sl@0: TRect* GetPosAnimation(const TUid& aUid); sl@0: TWsGraphicAnimation* SetAnimation(TUid); sl@0: TWsGraphicAnimation* GetAnimation(TUid); sl@0: TBool RemoveAnimation(TUid); sl@0: inline void SetBlankIt(TBool aNewVal) {iBlankIt = aNewVal;}; sl@0: inline void SetRepeatDrawMax(TInt aVal) {iRepeatDrawMax = aVal;}; sl@0: protected: sl@0: static void Draw(CBitmapContext *aGc, const TSize &aSize, TBool aIsBase,const TRect &aRect, TBool aBlankIt,TInt aRepeat, TInt aAlphaValue); sl@0: static void DrawEllipse(CBitmapContext *aGc, const TRect &aRect, TInt aAlphaValue); sl@0: CTBaseWin *iCtWin; sl@0: TWinType iWinType; sl@0: TBool iIsBase; sl@0: TBool iBlankIt; sl@0: TRect iRect; sl@0: TInt iRepeatDrawMax; sl@0: static CGraphicsContext::TDrawMode iEllipseDrawMode; sl@0: TUid iAnimUid; sl@0: TWsGraphicAnimation iAnimData; sl@0: TRect iAnimPos; sl@0: TInt iAlphaValue; sl@0: }; sl@0: sl@0: /* Using this time delay class in order to allow animations to play in our draw. sl@0: User::Wait does not allow the draw to occur (aparrently) sl@0: Note when using this time-delay class: because other active objects can perform part of their sl@0: processing whilst we wait, wrapping calls to this in __UHEAP_MARK / __UHEAP_MARKEND sl@0: is likely to fail. The data providers and animators are a major cause of this. sl@0: */ sl@0: class CActiveWait : public CActive sl@0: { sl@0: public: sl@0: static CActiveWait* NewL(); sl@0: ~CActiveWait(); sl@0: void Wait(TInt aDelay); sl@0: // From CActive: sl@0: void RunL(); sl@0: void DoCancel(); sl@0: TInt RunError(TInt aError); sl@0: protected: sl@0: CActiveWait(); sl@0: void ConstructL(); sl@0: protected: sl@0: RTimer iTimer; sl@0: TTime iFromTime; sl@0: }; sl@0: sl@0: CActiveWait* CActiveWait::NewL() sl@0: { sl@0: CActiveWait* self = new (ELeave) CActiveWait; sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: void CActiveWait::ConstructL() sl@0: { sl@0: User::LeaveIfError(iTimer.CreateLocal()); sl@0: CActiveScheduler::Add(this); sl@0: } sl@0: sl@0: CActiveWait::CActiveWait() : CActive(EPriorityNormal) sl@0: { sl@0: iFromTime.HomeTime(); sl@0: } sl@0: sl@0: CActiveWait::~CActiveWait() sl@0: { sl@0: Cancel(); sl@0: iTimer.Close(); sl@0: } sl@0: sl@0: void CActiveWait::DoCancel() sl@0: { sl@0: iTimer.Cancel(); sl@0: CActiveScheduler::Stop(); sl@0: } sl@0: sl@0: void CActiveWait::RunL() sl@0: { sl@0: CActiveScheduler::Stop(); sl@0: } sl@0: sl@0: TInt CActiveWait::RunError(TInt aError) sl@0: { sl@0: return aError; // exists so a break point can be placed on it. sl@0: } sl@0: sl@0: /* Note when using this : because other active objects can perform part of their sl@0: processing whilst we wait, wrapping calls to this in __UHEAP_MARK / __UHEAP_MARKEND sl@0: is likely to fail. The data providers and animators are a major cause of this. sl@0: */ sl@0: void CActiveWait::Wait(TInt aDelay) sl@0: { sl@0: iTimer.After(iStatus, aDelay); sl@0: SetActive(); sl@0: CActiveScheduler::Start(); sl@0: } sl@0: CGraphicsContext::TDrawMode CCrpAnim::iEllipseDrawMode; sl@0: sl@0: // sl@0: } //end anonymous local scope sl@0: // sl@0: sl@0: /** This fn allocates an animation frame of the specified dimensions. sl@0: Not tested outside the current limited parameter set (16/2/2007). sl@0: Note the use of 32-bit integers for pixel/colour values. Using display mode lower than 24bpp may not produce correct results sl@0: My attempt to write animation generating code that avoids CIclLoader and Decoder class. sl@0: @param aDelayUs the display time for the frame sl@0: @param aImageType Colour format for colour plane. 24MA currently not flagged correctly I expect. sl@0: @param aMaskType Format for mask. ENone for no mask. sl@0: @param aImageSize Width/height of bitmap area sl@0: @param aImageOffset Optional offset for bitmap area sl@0: @param aTotalSize Optional width/height of whole animation (I think) sl@0: @return CFrame filled in with allocated bitmaps. The get methods for the bitmaps return const type. sl@0: **/ sl@0: static CWsGraphicBitmapAnimation::CFrame* NewFrameLC(TInt aDelayUs,TDisplayMode aImageType,TDisplayMode aMaskType,const TSize& aImageSize,const TPoint& aImageOffset=KPointZero,const TSize& aTotalSize=TSize(0,0)) sl@0: { sl@0: TFrameInfo info; sl@0: info.iFrameCoordsInPixels = TRect(aImageOffset,aImageSize); sl@0: info.iFrameSizeInTwips = aImageSize; //this is zero in the gif loader sl@0: info.iDelay = TTimeIntervalMicroSeconds(aDelayUs); sl@0: info.iFlags = TFrameInfo::EColor|TFrameInfo::ELeaveInPlace|TFrameInfo::EUsesFrameSizeInPixels; sl@0: if (aMaskType != ENone) sl@0: { sl@0: info.iFlags|=TFrameInfo::ETransparencyPossible; sl@0: } sl@0: if ((aTotalSize.iHeight > 0) && (aTotalSize.iWidth > 0)) sl@0: { sl@0: // restrict the size of the frame to specified size of the animation sl@0: info.iOverallSizeInPixels = aTotalSize; sl@0: } sl@0: else sl@0: { sl@0: // assign the size of the frame to the size of the entire bitmap area sl@0: info.iOverallSizeInPixels = info.iFrameCoordsInPixels.iBr.AsSize(); sl@0: } sl@0: info.iFrameDisplayMode = aImageType; sl@0: info.iBackgroundColor = KRgbGreen; sl@0: sl@0: CWsGraphicBitmapAnimation::CFrame* frame = CWsGraphicBitmapAnimation::CFrame::NewL(); sl@0: CleanupStack::PushL(frame); sl@0: frame->SetFrameInfo(info); sl@0: CFbsBitmap* bitmap = new(ELeave) CFbsBitmap; sl@0: frame->SetBitmap(bitmap); //takes ownership sl@0: TSize frameInfoSize = info.iFrameCoordsInPixels.Size(); sl@0: User::LeaveIfError(bitmap->Create(frameInfoSize, aImageType)); sl@0: if((TFrameInfo::EAlphaChannel|TFrameInfo::ETransparencyPossible) & info.iFlags) sl@0: { sl@0: CFbsBitmap* mask = new(ELeave) CFbsBitmap; sl@0: frame->SetMask(mask); //takes ownership sl@0: User::LeaveIfError(mask->Create(frameInfoSize, aMaskType)); sl@0: } sl@0: return frame; sl@0: } sl@0: sl@0: // sl@0: // function called back by TCleanupItem frameListCleanup from within CreateAnimFramesL(..) method sl@0: // sl@0: void CleanupFrameList(TAny* aPtr) sl@0: { sl@0: RPointerArray* ptrArray = STATIC_CAST(RPointerArray*, aPtr); sl@0: ptrArray->ResetAndDestroy(); sl@0: ptrArray->Close(); sl@0: } sl@0: sl@0: /** Helper function for making animation frames. sl@0: //Called from CreateAnimL(...) sl@0: @param aDelayUs the delay between frames sl@0: @param aNumFrames number of frames (approx - image width is a factor) sl@0: @param aImageType colour format of colour data. This may not work properly for non-32-bit, but I haven't fully understood TBitmapUtil documentation. sl@0: @param aMaskType format for mask - ENone for no mask. sl@0: @param aImageSize width/height of animation sl@0: @param aBgCol background colour for image non-masked areas. Masked areas are black. sl@0: @param aFgCol foreground colour of animating area sl@0: @param aFrames frames that the animation is constructed from sl@0: **/ sl@0: static void CreateAnimFramesL(TInt aDelayUs,TInt aNumFrames,TDisplayMode aImageType,TDisplayMode aMaskType,TSize aImageSize,TRgb aBgCol,TRgb aFgCol, RPointerArray& aFrames) sl@0: { sl@0: const TInt animWH = aImageSize.iWidth; sl@0: const TInt animStep = Max(1,animWH/Max(1,aNumFrames)); //note this intentionally rounds down to avoid overflows sl@0: for (TInt ii = 0 ; ii < animWH ; ii += animStep) sl@0: { sl@0: CWsGraphicBitmapAnimation::CFrame* frame = NewFrameLC(aDelayUs,aImageType,aMaskType,aImageSize,KPointZero,aImageSize); sl@0: aFrames.AppendL(frame); sl@0: CleanupStack::Pop(frame); sl@0: TBitmapUtil utilMask(CONST_CAST(CFbsBitmap*, frame->Mask())); sl@0: TBitmapUtil utilCol(CONST_CAST(CFbsBitmap*, frame->Bitmap())); sl@0: utilCol.Begin(KPointZero); sl@0: sl@0: // cycle through the frame's actual bitmap & assign each pixel a value identical to the specified colours sl@0: TUint32 colback=aBgCol.Internal(); sl@0: TUint32 colfront=aFgCol.Internal(); sl@0: TInt row = KErrNone; sl@0: TInt col = KErrNone; sl@0: for (row = 0 ; row < aImageSize.iHeight ; row++) sl@0: { sl@0: utilCol.SetPos(TPoint(0, row)); sl@0: for (col = 0 ; col < aImageSize.iWidth ; col++) sl@0: { sl@0: utilCol.SetPixel(colback); sl@0: utilCol.IncXPos(); sl@0: } sl@0: utilCol.SetPos(TPoint(ii, row)); sl@0: for (col = 0 ; col < animStep ; col++) //Note I rely on intentional rounding down here! sl@0: { sl@0: utilCol.SetPixel(colfront); sl@0: utilCol.IncXPos(); sl@0: } sl@0: } sl@0: sl@0: if (aMaskType) sl@0: { sl@0: // cycle through each pixel of the frame's mask & assign a default pixel a colour value sl@0: utilMask.Begin(KPointZero); sl@0: for (row = 0 ; row < aImageSize.iHeight ; row++) sl@0: { sl@0: utilMask.SetPos(TPoint(0,row)); sl@0: for (col = 0 ; col < aImageSize.iWidth ; col++) sl@0: { sl@0: utilMask.SetPixel(KWhitePixels); sl@0: utilMask.IncXPos(); sl@0: } sl@0: } sl@0: sl@0: const TInt maxmaskWidth = Min(8,Max(animWH/3,2)); sl@0: sl@0: //cut the corners off the mask sl@0: for (row = 0 ; row < maxmaskWidth ; row++) sl@0: { sl@0: TInt currentX = maxmaskWidth - row; sl@0: TInt xPos = KErrNone; sl@0: sl@0: utilCol.SetPos(TPoint(0,row)); sl@0: utilMask.SetPos(TPoint(0,row)); sl@0: for(xPos = currentX ; xPos >= 0 ; xPos--) sl@0: { sl@0: utilCol.SetPixel(KBlackPixels); sl@0: utilCol.IncXPos(); sl@0: utilMask.SetPixel(KBlackPixels); sl@0: utilMask.IncXPos(); sl@0: } sl@0: sl@0: utilCol.SetPos(TPoint(animWH - 1, row)); sl@0: utilMask.SetPos(TPoint(animWH - 1, row)); sl@0: for(xPos = currentX ; xPos >= 0 ; xPos--) sl@0: { sl@0: utilCol.SetPixel(KBlackPixels); sl@0: utilCol.DecXPos(); sl@0: utilMask.SetPixel(KBlackPixels); sl@0: utilMask.DecXPos(); sl@0: } sl@0: sl@0: utilCol.SetPos(TPoint(0, animWH - 1 - row)); sl@0: utilMask.SetPos(TPoint(0, animWH - 1 - row)); sl@0: for(xPos = currentX ; xPos >= 0 ; xPos--) sl@0: { sl@0: utilCol.SetPixel(KBlackPixels); sl@0: utilCol.IncXPos(); sl@0: utilMask.SetPixel(KBlackPixels); sl@0: utilMask.IncXPos(); sl@0: } sl@0: sl@0: utilCol.SetPos(TPoint(animWH - 1, animWH - 1 - row)); sl@0: utilMask.SetPos(TPoint(animWH - 1, animWH - 1 - row)); sl@0: for(xPos = currentX ; xPos >= 0 ; xPos--) sl@0: { sl@0: utilCol.SetPixel(KBlackPixels); sl@0: utilCol.DecXPos(); sl@0: utilMask.SetPixel(KBlackPixels); sl@0: utilMask.DecXPos(); sl@0: } sl@0: } sl@0: utilMask.End(); sl@0: } sl@0: utilCol.End(); sl@0: } sl@0: } sl@0: sl@0: /** My attempt to write animation generating code that avoids CIclLoader and Decoder class. sl@0: //It is better if this test class used it's own generated animation sl@0: //rather than relying on the GIF loader in order to reduce the cross-dependencies. sl@0: //The animation generated is a simple vertical line moving from left to right. sl@0: //To prove the masking, I cut the corners off. sl@0: @param aDelayUs the delay between frames sl@0: @param aNumFrames number of frames (approx - image width is a factor) sl@0: @param aImageType colour format of colour data. This may not work properly for non-32-bit, but I haven't fully understood TBitmapUtil documentation. sl@0: @param aMaskType format for mask - ENone for no mask. sl@0: @param aImageSize width/height of animation sl@0: @param aBgCol background colour for image non-masked areas. Masked areas are black. sl@0: @param aFgCol foreground colour of animating area sl@0: @param aTUid TUid assigned to animation sl@0: @return CWsGraphicBitmapAnimation allocated to represent the final animation sl@0: **/ sl@0: static CWsGraphicBitmapAnimation* CreateAnimL(TInt aDelayUs,TInt aNumFrames,TDisplayMode aImageType,TDisplayMode aMaskType,TSize aImageSize,TRgb aBgCol,TRgb aFgCol,TUid& aTUid) sl@0: { sl@0: RPointerArray frames; sl@0: TCleanupItem frameListCleanup(CleanupFrameList, &frames); sl@0: CleanupStack::PushL(frameListCleanup); sl@0: sl@0: CreateAnimFramesL(aDelayUs, aNumFrames, aImageType, aMaskType, aImageSize,aBgCol, aFgCol, frames); sl@0: sl@0: CWsGraphicBitmapAnimation* anim = CWsGraphicBitmapAnimation::NewL(aTUid,frames.Array()); sl@0: CleanupStack::PopAndDestroy(&frames); sl@0: return anim; sl@0: } sl@0: sl@0: // sl@0: // Describes the pure colour of the RGB value. yellow/magenta/cyan set 2 bits. White/grey is seperately flagged. sl@0: // This method attempts to determine the strongest primary colour present in any given pixel. sl@0: // Note: The algorithm used is known to work for the current test cases only but requires careful review sl@0: // for anyone making additional changes to tcrpanim. Given time, improved algorithm should be developed sl@0: // to replace the current one sl@0: // sl@0: TUint PredominantColour(TUint aCol) sl@0: { //I don't like all these ifs, but I don't see an easy alternative sl@0: //Possibly a bit look-up of the deltas from average would work sl@0: //(ignoring the bottom 5 bits =32, not 0x30=48. Ignore bottom 4 bits and accept 3-same answers, or divide by delta?) sl@0: // sl@0: const TInt Kdelta=0x30; sl@0: TInt red=(aCol&0x00ff0000)>>16; sl@0: TInt green=(aCol&0x0000ff00)>>8; sl@0: TInt blue=(aCol&0x000000ff); sl@0: TInt ave=((red+green+blue)*(65536/3))>>16; sl@0: TBool rOverA=(red>ave); sl@0: TBool gOverA=(green>ave); sl@0: TBool bOverA=(blue>ave); sl@0: TInt numOverAve=(rOverA?1:0)+(gOverA?1:0)+(bOverA?1:0); sl@0: sl@0: if (numOverAve==1) sl@0: { sl@0: if (rOverA) sl@0: { sl@0: if (red>ave+Kdelta) sl@0: { sl@0: if ((green-blue)>-Kdelta && (green-blue)ave-Kdelta && blue>ave-Kdelta) sl@0: { sl@0: if (ave>256-Kdelta) sl@0: return EDetWhite; sl@0: else sl@0: return EDetGrey; sl@0: } sl@0: } sl@0: } sl@0: } sl@0: sl@0: if (gOverA) sl@0: { sl@0: if (green>ave+Kdelta) sl@0: { sl@0: if ((blue-red)>-Kdelta && (blue-red)ave-Kdelta && blue>ave-Kdelta) sl@0: if (ave>256-Kdelta) sl@0: return EDetWhite; sl@0: else sl@0: return EDetGrey; sl@0: } sl@0: } sl@0: } sl@0: sl@0: if (bOverA) sl@0: { sl@0: if (blue>ave+Kdelta) sl@0: { sl@0: if ((green-red)>-Kdelta && (green-red)ave-Kdelta && green>ave-Kdelta) sl@0: if (ave>256-Kdelta) sl@0: return EDetWhite; sl@0: else sl@0: return EDetGrey; sl@0: } sl@0: } sl@0: } sl@0: } sl@0: else sl@0: { sl@0: if (!rOverA) sl@0: if (red-Kdelta && (green-blue)256-Kdelta) sl@0: return EDetWhite; sl@0: else sl@0: { sl@0: if (blue-Kdelta && (blue-red)256-Kdelta) sl@0: return EDetWhite; sl@0: else sl@0: { sl@0: if (blue-Kdelta && (green-red)256-Kdelta) sl@0: return EDetWhite; sl@0: else sl@0: { sl@0: if (rediGroup->WinTreeNode()->SetOrdinalPosition(0); sl@0: iRedrawWin=new(ELeave) CCrpAnim(EFalse, CCrpAnim::ERedraw); sl@0: iBaseWin=new(ELeave) CCrpAnim(EFalse, CCrpAnim::ERedraw); sl@0: iOverWin=new(ELeave) CCrpAnim(EFalse, CCrpAnim::ERedraw); sl@0: sl@0: TSize screenSize=TheClient->iGroup->Size(); sl@0: TInt winWidth=(screenSize.iWidth/3)-10; sl@0: TInt winHeight=screenSize.iHeight-10; sl@0: TSize windowSize(winWidth,winHeight); sl@0: sl@0: iRedrawWin->ConstructL(TPoint(screenSize.iWidth/3*2+5,5), windowSize); sl@0: iBaseWin->ConstructL(TPoint(screenSize.iWidth/3+5,5), windowSize); sl@0: sl@0: //Create a transparent window that exactly overlaps the test window sl@0: //If transparency is not supported the leave causes the window to be destroyed and set to NULL. sl@0: //There is a test for transparency supported, but that simply creates a temp window to test anyway... sl@0: sl@0: //Note that when I originally wrote this test to fix PDEF101991, it generated white areas that I detected. sl@0: //However, if this transparent window used for extended tests is created over the test window, sl@0: //that somehow stops the white fill from occurring. sl@0: //The fault still occurs, but the previous screen contents are left behind. sl@0: //So now this window is created at an off-screen location. sl@0: TRAPD(err, iOverWin->ConstructL(KPointOffsite, windowSize, 0x80); iOverWin->SetBlankIt(ETrue); iOverWin->SetRepeatDrawMax(KMaxRepeatDraw);); sl@0: if (err) sl@0: { sl@0: delete iOverWin; sl@0: iOverWin = NULL; sl@0: } sl@0: sl@0: iTestWin = iRedrawWin; sl@0: iTestWin->SetRepeatDrawMax(KMaxRepeatDraw); sl@0: iBaseWin->SetRepeatDrawMax(KMaxRepeatDraw); sl@0: sl@0: // create animation object & share it with everyone sl@0: iAnim = CreateAnimL(KAnimationFrameDelayTime,KAnimationTotalFrames,KTestDisplayMode,EGray256,TSize(KAnimDimension, KAnimDimension),KRgbBlue,KRgbRed,KUidTestAnimation2); sl@0: if (!iAnim) sl@0: { sl@0: User::Leave(KErrNoMemory); sl@0: } sl@0: iAnim->ShareGlobally(); sl@0: sl@0: // calculate minimum length of the red line sl@0: const TInt maxmaskHeight = Min(8, Max(KAnimDimension/3,2)); // note this calculation mimics that for the size of the corners cut from the mask in CreateAnimL above sl@0: iMinimumCalcRedLine = KAnimDimension - maxmaskHeight*2; // the height of the image minus the two cut corners sl@0: sl@0: // create the timer object sl@0: iWaiter = CActiveWait::NewL(); sl@0: sl@0: // create screen bitmap object & scanline buffer sl@0: iScreenBitmap = new (ELeave) CFbsBitmap; sl@0: User::LeaveIfError(iScreenBitmap->Create(TSize(KAnimDimension, KAnimDimension), KTestDisplayMode)); sl@0: TInt bufLength = iScreenBitmap->ScanLineLength(windowSize.iHeight, KTestDisplayMode); sl@0: iScanlineBuf = HBufC8::NewL(bufLength); sl@0: sl@0: #ifdef RUN_SAMPLE_ON_LEFT sl@0: { sl@0: // play animation on iBaseWin window sl@0: iBaseWin->SetAnimation(KUidTestAnimation2)->Play(ETrue); sl@0: TSize subsize1 = iTestWin->BaseWin()->Size(); sl@0: TRect subposition1(subsize1); sl@0: CalcCentredAnimPosition(subposition1, subsize1); sl@0: iBaseWin->SetPosAnimation(KUidTestAnimation2, subposition1); sl@0: iBaseWin->InvalidateAndRedraw(ETrue,EFalse,ETrue); sl@0: } sl@0: #endif sl@0: } sl@0: sl@0: CTCrpAnim::~CTCrpAnim() sl@0: { sl@0: delete iRedrawWin; sl@0: delete iBaseWin; sl@0: delete iOverWin; sl@0: if (iAnim) sl@0: { sl@0: // destroy the animation object sl@0: iAnim->UnShareGlobally(); sl@0: iAnim->Destroy(); sl@0: delete iAnim; sl@0: iAnim = NULL; sl@0: } sl@0: if (iWaiter) sl@0: { sl@0: // destroy the timer object sl@0: delete iWaiter; sl@0: iWaiter = NULL; sl@0: } sl@0: if (iScreenBitmap) sl@0: { sl@0: // destroy the screen capture of the animation sl@0: delete iScreenBitmap; sl@0: iScreenBitmap = NULL; sl@0: } sl@0: if (iScanlineBuf) sl@0: { sl@0: // destroy the scanline buffer sl@0: delete iScanlineBuf; sl@0: iScanlineBuf = NULL; sl@0: } sl@0: User::After(200000); sl@0: } sl@0: sl@0: // sl@0: // This method checks the animation contained in the aAnimWin window has progressed. That is sl@0: // that it's drawn a sufficient number of concurrent frames to screen & the animation is sl@0: // drawn properly to screen sl@0: // returns a Bool identifying whether the animation is considered 'good' or not sl@0: // sl@0: void CTCrpAnim::CheckAnimProgressedL(CAnonAnimWindow* aAnimWin, TInt aAdditionalFrameCount, TBool aCaptureFrameResult) sl@0: { sl@0: TBool goodAnimation = ETrue; sl@0: sl@0: // retrieve the rect from the screen's bitmap that contains the animation sl@0: CWsScreenDevice* screen = TheClient->iScreen; sl@0: TRect animPos = *aAnimWin->GetPosAnimation(KUidTestAnimation2); sl@0: CTBaseWin* bWin = aAnimWin->CtBaseWin(); sl@0: animPos.Move(bWin->Position()); sl@0: User::LeaveIfError(screen->CopyScreenToBitmap(iScreenBitmap, animPos)); sl@0: sl@0: TInt frameNum = DetermineApproxFrameNum(iScreenBitmap, aCaptureFrameResult); // determines the frame Number & checks quality of animation (no tearing, etc) sl@0: TBool frameIdentified=(frameNum>=0); sl@0: sl@0: if (aCaptureFrameResult) sl@0: { sl@0: if (frameIdentified) sl@0: { sl@0: if (iPreviousFrameNum != KErrNotFound) sl@0: { sl@0: if (iPreviousFrameNum < frameNum) sl@0: { sl@0: TInt frameStep = KFrameStepCalculation * aAdditionalFrameCount; sl@0: iPreviousFrameNum += frameStep; // move to our *expected* framenumber sl@0: if (frameNum > iPreviousFrameNum) sl@0: { sl@0: // the frame number is ahead of it's expected position sl@0: // This suggests we've possibly missed animating a frame in wserv sl@0: // or test code isn't getting a chance to execute as crp animations taking all cpu cycles sl@0: // If its significantly outside norms, we log the fact (as a performance metric) sl@0: TInt performance = ((frameNum - iPreviousFrameNum) / frameStep); sl@0: if (performance > KFrameMissedAnimationsThreshold) sl@0: { sl@0: iFrameStatus.iFrameSkipped++; sl@0: goodAnimation = EFalse; sl@0: } sl@0: } sl@0: // else we're animating above an acceptable threshold sl@0: } sl@0: else if (iPreviousFrameNum == frameNum) // potentially not animating anymore sl@0: { sl@0: iFrameStatus.iFrameIdentical++; sl@0: goodAnimation = EFalse; sl@0: } sl@0: // else animation is progressing fine sl@0: } sl@0: // ignore iPreviousFrameNum == KErrNotFound sl@0: } sl@0: else sl@0: { sl@0: goodAnimation = EFalse; // couldn't id the red line sl@0: } sl@0: sl@0: if (goodAnimation) sl@0: { sl@0: iFrameStatus.iFrameOK++; sl@0: } sl@0: } sl@0: // else we were only interested in calculating the frameNum sl@0: iPreviousFrameNum = frameNum; sl@0: } sl@0: sl@0: // sl@0: // method to estimate the framenumber based on the location of the thin, red line. sl@0: // Also checks whether tearing of the animation has occured or the animation sl@0: // is only partially drawn. sl@0: // These are known issues with wserv animation performance & so we give some allowance for error sl@0: // sl@0: TInt CTCrpAnim::DetermineApproxFrameNum(CFbsBitmap* aBitmap, TBool aCaptureFrameResult) sl@0: { sl@0: TInt colFirstTear = KErrNotFound; // column id'ing the first tear in the vertical line sl@0: TPtr8 des = iScanlineBuf->Des(); // ptr to the scanline buffer sl@0: sl@0: // locate the thin, red line in the bitmap sl@0: for (TInt xPos = 0 ; xPos < aBitmap->SizeInPixels().iWidth ; xPos++) sl@0: { sl@0: aBitmap->GetVerticalScanLine(des, xPos, EColor16MA); sl@0: TUint32* pixel = (TUint32*) des.Ptr(); sl@0: TInt colour = KErrNone; sl@0: sl@0: for (TInt ii = 0 ; ii < aBitmap->SizeInPixels().iHeight ; ii++) sl@0: { sl@0: colour = PredominantColour(*pixel); sl@0: if (colour & EDetRed) sl@0: { sl@0: if (colFirstTear < 0) sl@0: { sl@0: // check the length of the red line is a good length sl@0: pixel += (iMinimumCalcRedLine - 1); // minus the one pixel to position on last pixel in red line sl@0: colour = PredominantColour(*pixel); sl@0: if (colour & EDetRed) sl@0: { sl@0: // good line sl@0: return xPos; sl@0: } sl@0: else // we've detected first part of a torn line sl@0: { sl@0: colFirstTear = xPos; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // located second part of torn line sl@0: if ((xPos - colFirstTear) > KAnimationTearWidthThreshold) sl@0: { sl@0: if (aCaptureFrameResult) sl@0: { sl@0: iFrameStatus.iFrameTearing++; sl@0: } sl@0: xPos = KErrNotFound; sl@0: } sl@0: return xPos; sl@0: } sl@0: break; sl@0: } sl@0: pixel++; sl@0: } sl@0: } sl@0: if (aCaptureFrameResult) sl@0: { sl@0: if (colFirstTear < 0) sl@0: { sl@0: iFrameStatus.iFrameEmpty++; // we never located any red line at all sl@0: } sl@0: else sl@0: { sl@0: iFrameStatus.iFramePartial++; // we only located a single, small part of the red line sl@0: } sl@0: } sl@0: return KErrNotFound; sl@0: } sl@0: sl@0: /** This internal loop tests that the animation and the foreground interact correctly sl@0: The primary test is that the outline of the animation sl@0: intersects the lines drawn on the foreground correctly, compared to a reference version. sl@0: The iBaseWin is already showing this reference anim. sl@0: If the animation is not drawn, or the foreground is wiped, then this test will fail. sl@0: **/ sl@0: void CTCrpAnim::TestSpriteLoopL(TBool aAnimForeground,TBool aDrawForeground) sl@0: { sl@0: _LIT(KForegroundInfo,"TestSpriteLoop animForeground [%d] drawForeground [%d]"); sl@0: INFO_PRINTF3(KForegroundInfo, aAnimForeground, aDrawForeground); sl@0: sl@0: if (!iOverWin && (aAnimForeground || aDrawForeground)) sl@0: { sl@0: User::Leave(KErrGeneral); // unable to run this test without iOverWin sl@0: } sl@0: sl@0: ResetFrameCounters(); sl@0: iTestWin->RemoveAnimation(KUidTestAnimation2); sl@0: iTestWin->SetBlankIt(ETrue); sl@0: if (iOverWin) sl@0: { sl@0: iOverWin->RemoveAnimation(KUidTestAnimation2); sl@0: iOverWin->SetBlankIt(ETrue); sl@0: } sl@0: sl@0: // determine which window holds the animation, & which will be invalidated with progressively larger rects sl@0: CCrpAnim* animWin=aAnimForeground?iOverWin:iTestWin; sl@0: CCrpAnim* paintWin=aDrawForeground?iOverWin:iTestWin; sl@0: paintWin->SetBlankIt(EFalse); sl@0: sl@0: // set & play the animation on the specified window (animWin) sl@0: animWin->SetAnimation(KUidTestAnimation2)->Play(ETrue); sl@0: TSize subsize1 = paintWin->BaseWin()->Size(); sl@0: TRect subposition1(subsize1); sl@0: CalcCentredAnimPosition(subposition1, subsize1); sl@0: animWin->SetPosAnimation(KUidTestAnimation2, subposition1); sl@0: sl@0: #ifdef RUN_SAMPLE_ON_LEFT sl@0: // play the demo animation in the left-hand window also sl@0: iBaseWin->InvalidateAndRedraw(ETrue, EFalse, ETrue); sl@0: #endif sl@0: sl@0: iTestWin->InvalidateAndRedraw(ETrue,EFalse,ETrue); sl@0: if (iOverWin) sl@0: { sl@0: iOverWin->InvalidateAndRedraw(ETrue,EFalse,ETrue); sl@0: } sl@0: sl@0: // invalidate increasingly larger squares on paintWin sl@0: // note, some fully overlap the animation, some partially overlap, and some don't overlap at all sl@0: TInt invalidateWaitTime=KAnimationFrameDelayTime*3/4; // microseconds sl@0: TInt temp = KErrNotFound; sl@0: for (TInt step=30;stepInvalidateAndRedraw(ETrue,EFalse,ETrue,&invalidRect); sl@0: sl@0: // calculate any additional frames that may be drawn by above. Note intentionally ignore frame result sl@0: temp = iPreviousFrameNum; sl@0: CheckAnimProgressedL(animWin, 1, EFalse); sl@0: sl@0: //new defect DEF101896: Test runs faster with this line removed, but there is evident tearing sl@0: iWaiter->Wait(invalidateWaitTime); //DEF101896 search string: //interrupt_foreground_draw sl@0: sl@0: if (temp == iPreviousFrameNum) sl@0: { sl@0: // give wserv more time to animate the frame sl@0: iWaiter->Wait(invalidateWaitTime); sl@0: } sl@0: CheckAnimProgressedL(animWin, 1); // calculate the frame drawn. Capture frame result sl@0: } sl@0: } sl@0: } sl@0: sl@0: // determine whether the animation was successful (ie: enough Good frames were detected) or not sl@0: // Note KMinGoodFrameThreshold is essentially an arbitrary number. This can be adjusted to accommodate sl@0: // performance requirements as needed sl@0: temp = LogResults(); sl@0: TInt quality = 100*iFrameStatus.iFrameOK/temp; sl@0: TEST(quality > KMinGoodFrameThreshold); sl@0: sl@0: ResetFrameCounters(); sl@0: iWaiter->Cancel(); sl@0: iTestWin->RemoveAnimation(KUidTestAnimation2); sl@0: iTestWin->SetBlankIt(ETrue); sl@0: if (iOverWin) sl@0: { sl@0: iOverWin->RemoveAnimation(KUidTestAnimation2); sl@0: iOverWin->SetBlankIt(ETrue); sl@0: } sl@0: } sl@0: sl@0: // sl@0: // resets the frame trackers to intial values sl@0: // sl@0: void CTCrpAnim::ResetFrameCounters() sl@0: { sl@0: iPreviousFrameNum = KErrNotFound; sl@0: iFrameStatus.iFrameOK = 0; sl@0: iFrameStatus.iFramePartial = 0; sl@0: iFrameStatus.iFrameIdentical = 0; sl@0: iFrameStatus.iFrameEmpty = 0; sl@0: iFrameStatus.iFrameTearing = 0; sl@0: iFrameStatus.iFrameSkipped = 0; sl@0: } sl@0: sl@0: // sl@0: // Log the current frame results & return the total number of frame calculations sl@0: // sl@0: // Calculated : the total number of frame-checks run sl@0: // Good: the frame was successfully drawn to screen & within specified tolerances for tearing, expected position & colour sl@0: // Partial: the frame was only partially drawn to screen. Specifcally the animated red line was only partially drawn sl@0: // Identical: the frame was in the same position as the last frame sl@0: // Empty: no redline was detected at all in the frame sl@0: // Skipped: the position of the frame was beyond the expected position sl@0: // sl@0: // There is a dependency on the timing as to when the frame is animated hence tolerances are used to allow sl@0: // for this. sl@0: // sl@0: TInt CTCrpAnim::LogResults() sl@0: { sl@0: TInt result = iFrameStatus.iFrameOK + iFrameStatus.iFramePartial + iFrameStatus.iFrameIdentical + sl@0: iFrameStatus.iFrameEmpty + iFrameStatus.iFrameTearing + iFrameStatus.iFrameSkipped; sl@0: INFO_PRINTF4(_L("\tAnimation results: Calculated[%d], Good[%d], Partial[%d]"), result, iFrameStatus.iFrameOK, iFrameStatus.iFramePartial); sl@0: INFO_PRINTF5(_L("\tAnimation results: Identical[%d], Empty[%d], Tearing[%d], Skipped[%d]"), iFrameStatus.iFrameIdentical, iFrameStatus.iFrameEmpty, iFrameStatus.iFrameTearing, iFrameStatus.iFrameSkipped); sl@0: return result; sl@0: } sl@0: sl@0: /** This test tests the result of drawing an animation and main draw to two windows that overlap. sl@0: The two windows are placed in exactly the same location, so the result of splitting the drawing across them should be "identical". sl@0: Note that when the anim and the draw are on different screens the lines are seen merged over the anim. sl@0: **/ sl@0: void CTCrpAnim::TestOverlappingWindowsL() sl@0: { sl@0: if (!iOverWin) sl@0: { sl@0: INFO_PRINTF1(_L("- Test skipped - transparency not supported")); sl@0: return; sl@0: } sl@0: sl@0: // setup necessary params sl@0: // Note we place the overlapping transparent window (iOverWin) directly on top of the test window (iTestWin) sl@0: iOverWin->BaseWin()->SetPosition(iTestWin->BaseWin()->Position()); sl@0: sl@0: enum sl@0: { sl@0: EAllBackground=0, sl@0: EForegroundDraw=1, sl@0: EForegroundAnim=2, sl@0: EAllForeGround=3, sl@0: ECountModes, sl@0: EFirstMode=EAllBackground, sl@0: }; sl@0: sl@0: // test the various permutations of overlapping vs animated windows sl@0: for (TInt mode = EFirstMode ; mode < ECountModes ; mode++) sl@0: { sl@0: INFO_PRINTF2(_L("TestOverlappingWindowsL [%d]"), mode); sl@0: TestSpriteLoopL((mode&EForegroundAnim)!=0,(mode&EForegroundDraw)!=0); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This method demonstrates clipping of an animation running behind a transparent window. sl@0: No main window redraw takes place here. sl@0: **/ sl@0: void CTCrpAnim::DemoClippingWindowsL() sl@0: { sl@0: if (!iOverWin) sl@0: { sl@0: INFO_PRINTF1(_L("- Test skipped - transparency not supported")); sl@0: return; sl@0: } sl@0: sl@0: // setup test case params. Note we calculate three different positions for the overlapping window sl@0: RWindow* win = iTestWin->Window(); sl@0: sl@0: TPoint screenPos= win->Position(); sl@0: TSize screenSize = win->Size(); sl@0: TRect subposition1(screenSize); sl@0: CalcCentredAnimPosition(subposition1, screenSize); sl@0: sl@0: TPoint testPositions[]= sl@0: { sl@0: //first test: window clips corner of anim sl@0: TPoint(screenPos.iX+screenSize.iWidth/2-10,screenPos.iY+screenSize.iHeight/2-10), sl@0: //test: window clips all of anim sl@0: TPoint(screenPos.iX+screenSize.iWidth/3,screenPos.iY+screenSize.iHeight/3), sl@0: //test: window clips none of anim sl@0: TPoint(screenPos.iX+screenSize.iWidth*2/3,screenPos.iY+screenSize.iHeight*2/3), sl@0: }; sl@0: sl@0: // calculate roughly number of frames we expect to have drawn sl@0: TInt loopWaitTime = KShortDelayLoop; // time given to allow animation to progress (arbitrary number) sl@0: float expectedFrameCount = 1; sl@0: if (loopWaitTime > KAnimationFrameDelayTime) sl@0: { sl@0: expectedFrameCount = loopWaitTime/KAnimationFrameDelayTime; sl@0: } sl@0: sl@0: for (TInt ii = 0; ii < ((sizeof testPositions)/(sizeof testPositions[0])) ; ii++) sl@0: { sl@0: // initialise test windows to known state with no active animations sl@0: ResetFrameCounters(); sl@0: iTestWin->RemoveAnimation(KUidTestAnimation2); sl@0: iTestWin->SetBlankIt(EFalse); sl@0: iOverWin->SetBlankIt(ETrue); sl@0: iOverWin->RemoveAnimation(KUidTestAnimation2); sl@0: sl@0: // position animation windows sl@0: iTestWin->SetAnimation(KUidTestAnimation2)->Play(ETrue); sl@0: iTestWin->SetPosAnimation(KUidTestAnimation2, subposition1); sl@0: iOverWin->BaseWin()->SetPosition(testPositions[ii]); // positions the transparent overlapping window sl@0: sl@0: // redraw both test windows sl@0: iTestWin->InvalidateAndRedraw(ETrue,EFalse,ETrue); sl@0: iOverWin->InvalidateAndRedraw(ETrue,EFalse,ETrue); sl@0: sl@0: // run the animation for an arbitrary period sl@0: for (TInt loopit = 0 ; loopit < 20 ; loopit++) sl@0: { sl@0: iWaiter->Wait(loopWaitTime); sl@0: CheckAnimProgressedL(iTestWin,static_cast(expectedFrameCount)); // log the frame result sl@0: } sl@0: sl@0: // calculate & log frame results. Test an acceptable number of frames were successfully animated sl@0: TInt total = LogResults(); sl@0: TInt qA = 100*iFrameStatus.iFrameOK/total; sl@0: TEST(qA > KMinGoodFrameThreshold); sl@0: } sl@0: } sl@0: sl@0: /** In this version, the background window is updated in patches. sl@0: If the animation intersects the transparent window then the whole transparent window is redrawn. sl@0: **/ sl@0: void CTCrpAnim::TestClippingWindowsL() sl@0: { sl@0: if (!iOverWin) sl@0: { sl@0: INFO_PRINTF1(_L("- Test skipped - transparency not supported")); sl@0: return; sl@0: } sl@0: // setup test case params. Note we calculate three different positions for the overlapping window sl@0: RWindow* win = iTestWin->Window(); sl@0: TPoint screenPos= win->Position(); sl@0: TSize screenSize = win->Size(); sl@0: sl@0: TPoint testPositions[]= sl@0: { sl@0: //first test: window clips corner of anim sl@0: TPoint(screenPos.iX+screenSize.iWidth/2-10,screenPos.iY+screenSize.iHeight/2-10), sl@0: //test: window clips all of anim sl@0: TPoint(screenPos.iX+screenSize.iWidth/3,screenPos.iY+screenSize.iHeight/3), sl@0: //test: window clips none of anim sl@0: TPoint(screenPos.iX+screenSize.iWidth*2/3,screenPos.iY+screenSize.iHeight*2/3), sl@0: }; sl@0: sl@0: for (TInt loopIt = 0; loopIt < ((sizeof testPositions)/(sizeof testPositions[0])) ; loopIt++) sl@0: { sl@0: iOverWin->BaseWin()->SetPosition(testPositions[loopIt]); // position the overlapping window sl@0: TestSpriteLoopL(EFalse,EFalse); sl@0: } sl@0: } sl@0: sl@0: /** This just demonstrates that an animation plays - for about 1 second. sl@0: **/ sl@0: void CTCrpAnim::BasicCRPDemo() sl@0: { sl@0: // draw the animation in two positions sl@0: TSize subsize1 = iTestWin->BaseWin()->Size(); sl@0: TRect subposition1(subsize1); sl@0: CalcCentredAnimPosition(subposition1, subsize1); sl@0: sl@0: if (iOverWin) sl@0: { sl@0: iOverWin->BaseWin()->SetPosition(KPointOffsite); //way away! sl@0: iOverWin->InvalidateAndRedraw(EFalse,EFalse,ETrue); sl@0: } sl@0: sl@0: CCrpAnim *animWin= iTestWin; sl@0: animWin->SetAnimation(KUidTestAnimation2)->Play(ETrue); sl@0: animWin->SetPosAnimation(KUidTestAnimation2, subposition1); sl@0: iTestWin->InvalidateAndRedraw(ETrue,EFalse,ETrue); sl@0: iBaseWin->InvalidateAndRedraw(ETrue,EFalse,ETrue); sl@0: sl@0: // allow the animation to play for ~1 second. Purpose is to demonstrate animation to an observer sl@0: iWaiter->Wait(KShortDelayLoop); sl@0: sl@0: ResetFrameCounters(); sl@0: iWaiter->Cancel(); sl@0: iTestWin->RemoveAnimation(KUidTestAnimation2); sl@0: } sl@0: sl@0: /** sl@0: @SYMTestCaseID GRAPHICS-WSERV-CRP01-0001 sl@0: sl@0: @SYMDEF DEF100356 sl@0: sl@0: @SYMTestCaseDesc CRP animation test for redraw storing interrupting main draw sl@0: sl@0: @SYMTestPriority High sl@0: sl@0: @SYMTestStatus Implemented sl@0: sl@0: @SYMTestActions Creates a CRP animation and runs it on the server scheduler sl@0: while also running redraws of the window. sl@0: sl@0: With Redraw storing this has been known to cause problems sl@0: sharing and resetting the window iDisplayRegion. sl@0: This is evidenced by white areas. sl@0: sl@0: sl@0: @SYMTestExpectedResults sl@0: The LHS window shows what the animation should look like just animating, sl@0: while the RHS window demonstrates the simultanious animation and redraw. sl@0: No White patches should be in evidence, and no missing fragments of animation. sl@0: The TEST should detect white patches. sl@0: */ sl@0: void CTCrpAnim::TestSpriteInterruptsForegroundL() sl@0: { sl@0: // setup test params sl@0: TSize subsize1(iTestWin->BaseWin()->Size()); sl@0: TRect subposition1(subsize1); sl@0: CalcCentredAnimPosition(subposition1, subsize1); sl@0: if (iOverWin) sl@0: { sl@0: iOverWin->BaseWin()->SetPosition(KPointOffsite); // ensure overlapping transparent window DOESN'T overlap the test window sl@0: } sl@0: sl@0: // execute test loop sl@0: TestSpriteLoopL(EFalse,EFalse); sl@0: } sl@0: sl@0: void CTCrpAnim::RunTestCaseL(TInt /*aCurTestCase*/) sl@0: { sl@0: _LIT(KTest1,"1: Basic CRP demo"); sl@0: _LIT(KTest2,"2: sprite anim interrupts foreground"); sl@0: _LIT(KTest3,"3: translucent windows"); sl@0: _LIT(KTest4,"4: CRP clipping windows"); sl@0: _LIT(KTest5,"5: CRP & redraw clipping windows"); sl@0: _LIT(KTest6,"6: CRP Invalidation"); sl@0: sl@0: ((CTCrpAnimStep*)iStep)->SetTestStepID(KUnknownSYMTestCaseIDName); sl@0: switch(++iTest->iState) sl@0: { sl@0: case 1: sl@0: /** sl@0: @SYMTestCaseID GRAPHICS-WSERV-CRP01-0002 sl@0: */ sl@0: ((CTCrpAnimStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-CRP01-0002")); sl@0: iTest->LogSubTest(KTest1); sl@0: BasicCRPDemo(); sl@0: break; sl@0: case 2: sl@0: ((CTCrpAnimStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-CRP01-0001")); sl@0: iTest->LogSubTest(KTest2); sl@0: TestSpriteInterruptsForegroundL(); sl@0: break; sl@0: case 3: sl@0: /** sl@0: @SYMTestCaseID GRAPHICS-WSERV-CRP01-0003 sl@0: */ sl@0: ((CTCrpAnimStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-CRP01-0003")); sl@0: iTest->LogSubTest(KTest3); sl@0: TestOverlappingWindowsL(); sl@0: break; sl@0: case 4: sl@0: /** sl@0: @SYMTestCaseID GRAPHICS-WSERV-CRP01-0004 sl@0: */ sl@0: ((CTCrpAnimStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-CRP01-0004")); sl@0: iTest->LogSubTest(KTest4); sl@0: DemoClippingWindowsL(); sl@0: break; sl@0: case 5: sl@0: /** sl@0: @SYMTestCaseID GRAPHICS-WSERV-CRP01-0005 sl@0: */ sl@0: ((CTCrpAnimStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-CRP01-0005")); sl@0: iTest->LogSubTest(KTest5); sl@0: TestClippingWindowsL(); sl@0: break; sl@0: case 6: sl@0: /** sl@0: @SYMTestCaseID GRAPHICS-WSERV-CRP01-0006 sl@0: */ sl@0: ((CTCrpAnimStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-CRP01-0006")); sl@0: iTest->LogSubTest(KTest6); sl@0: //this testcase is removed, because invalidation is removed from CWsGraphicDrawer destructor (due to flickering) sl@0: break; sl@0: default: sl@0: ((CTCrpAnimStep*)iStep)->SetTestStepID(KNotATestSYMTestCaseIDName); sl@0: ((CTCrpAnimStep*)iStep)->CloseTMSGraphicsStep(); sl@0: TestComplete(); sl@0: } sl@0: ((CTCrpAnimStep*)iStep)->RecordTestResultL(); sl@0: } sl@0: sl@0: // sl@0: namespace //anonymous namespace sl@0: { sl@0: // sl@0: CAnimRedrawWindow::CAnimRedrawWindow(CCrpAnim *aAnimWindow, TBool aIsBase) : CTWin(), sl@0: iAnimWindow(aAnimWindow), sl@0: iIsBase(aIsBase) sl@0: { sl@0: } sl@0: sl@0: CAnimRedrawWindow::~CAnimRedrawWindow() sl@0: { sl@0: } sl@0: sl@0: void CAnimRedrawWindow::Draw() sl@0: { sl@0: CCrpAnim::Draw(Gc(),Size(),iIsBase,iAnimWindow->iRect,iAnimWindow->iBlankIt,iAnimWindow->iRepeatDrawMax,iAnimWindow->iAlphaValue); sl@0: if (iAnimWindow->iAnimUid!=TUid::Null()) sl@0: { sl@0: TheClient->Flush(); sl@0: Gc()->DrawWsGraphic(iAnimWindow->iAnimUid,iAnimWindow->iAnimPos,iAnimWindow->iAnimData.Pckg()); sl@0: TheClient->Flush(); sl@0: } sl@0: } sl@0: sl@0: // sl@0: sl@0: CCrpAnim::CCrpAnim(TBool aIsBase, TWinType aWinType) sl@0: : iWinType(aWinType), sl@0: iIsBase(aIsBase), sl@0: iBlankIt(EFalse), sl@0: iRepeatDrawMax(1), sl@0: iAnimUid(TUid::Null()), sl@0: iAlphaValue(ENoTransparency) sl@0: { sl@0: } sl@0: sl@0: CCrpAnim::~CCrpAnim() sl@0: { sl@0: delete iCtWin; sl@0: } sl@0: sl@0: void CCrpAnim::ConstructL(const TPoint &aPos, const TSize &aSize, TInt aAlphaValue) sl@0: { sl@0: TDisplayMode reqMode = EColor16MA; //for transparency we need 16ma or 16map mode sl@0: TDisplayMode *pReqMode=&reqMode; sl@0: switch(iWinType) sl@0: { sl@0: case ERedraw: sl@0: iCtWin = new(ELeave) CAnimRedrawWindow(this, iIsBase); sl@0: break; sl@0: case EBlank: sl@0: iCtWin = new(ELeave) CTBlankWindow(); sl@0: break; sl@0: case EBackedUp: sl@0: iCtWin = new(ELeave) CTBackedUpWin(EColor64K); sl@0: pReqMode = NULL; sl@0: break; sl@0: } sl@0: iCtWin->SetUpL(aPos, aSize, TheClient->iGroup, *TheClient->iGc, pReqMode, ETrue); sl@0: if (aAlphaValue != ENoTransparency) sl@0: { sl@0: User::LeaveIfError(Window()->SetTransparencyAlphaChannel()); sl@0: //the window itself should be completely transparent, the draw commands will use the alpha value sl@0: Window()->SetBackgroundColor(TRgb(0, 0, 0, 0)); sl@0: iAlphaValue = aAlphaValue; sl@0: } sl@0: } sl@0: sl@0: void CCrpAnim::SetEllipseDrawMode(CGraphicsContext::TDrawMode aEllipseDrawMode) sl@0: { sl@0: iEllipseDrawMode = aEllipseDrawMode; sl@0: } sl@0: sl@0: void CCrpAnim::DrawEllipse(CBitmapContext *aGc, const TRect &aRect, TInt aAlphaValue) sl@0: { sl@0: if(aAlphaValue != ENoTransparency) sl@0: { sl@0: aGc->SetBrushColor(TRgb(85,85,85, aAlphaValue)); sl@0: aGc->SetPenColor(TRgb(170,170,170, aAlphaValue)); sl@0: } sl@0: else sl@0: { sl@0: aGc->SetBrushColor(TRgb(85,85,85)); sl@0: aGc->SetPenColor(TRgb(170,170,170)); sl@0: } sl@0: aGc->SetDrawMode(iEllipseDrawMode); sl@0: aGc->SetBrushStyle(CGraphicsContext::ESolidBrush); sl@0: aGc->DrawEllipse(aRect); sl@0: } sl@0: sl@0: void CCrpAnim::Draw(CBitmapContext *aGc, const TSize &aSize, TBool aIsBase, const TRect &aRect, TBool aBlankIt,TInt aRepeat, TInt aAlphaValue) sl@0: { sl@0: static TInt sGrey=0; sl@0: sGrey+=3; sl@0: if (sGrey>0x40) sl@0: sGrey-=0x40; sl@0: sGrey=sGrey^0x20; sl@0: if(aAlphaValue != ENoTransparency) sl@0: { sl@0: aGc->SetBrushColor(TRgb(sGrey, sGrey, sGrey, aAlphaValue)); sl@0: aGc->SetPenColor(TRgb(KRgbGreen.Value(), aAlphaValue)); sl@0: } sl@0: else sl@0: { sl@0: aGc->SetBrushColor(TRgb::Gray256(sGrey)); sl@0: aGc->SetPenColor(KRgbGreen); sl@0: } sl@0: aGc->Clear(); sl@0: TInt xPos=aSize.iHeight,yPos=aSize.iWidth; sl@0: sl@0: // The test windows are created relative to screen size. The sl@0: // number of green lines generated needs to be tied into the sl@0: // window size to prevent green becoming the dominant colour sl@0: // when blended with the second animation, which would sl@0: // prevent the PredominantColour() algorithm from discovering sl@0: // the red line. sl@0: TInt yStep = aSize.iHeight/14; sl@0: TInt xStep = aSize.iWidth/6; sl@0: sl@0: //This paint is intentionally complex and slow so that the animation timer is likely to interrupt it. sl@0: if (!aBlankIt) sl@0: for (TInt nn = 0 ; nn < aRepeat ; nn++) sl@0: for(yPos=0 ; yPos < aSize.iHeight ; yPos += yStep) sl@0: for(xPos=0 ; xPos < aSize.iWidth ; xPos += xStep) sl@0: aGc->DrawLine(aRect.Center(),TPoint(xPos,yPos)); sl@0: if (aIsBase) sl@0: DrawEllipse(aGc, aRect, aAlphaValue); sl@0: } sl@0: sl@0: //This simple API may need replacing by a list and search if multiple anims are played together sl@0: TWsGraphicAnimation* CCrpAnim::SetAnimation(TUid aUid) sl@0: { //currently only have 1 animation - it gets replaced. It could get refiused sl@0: iAnimUid=aUid; sl@0: return &iAnimData; sl@0: } sl@0: sl@0: TWsGraphicAnimation* CCrpAnim::GetAnimation(TUid aUid) sl@0: { //currently only have 1 animation sl@0: if (iAnimUid==aUid) sl@0: return &iAnimData; sl@0: else sl@0: return NULL; sl@0: } sl@0: sl@0: void CCrpAnim::SetPosAnimation(const TUid& aUid, const TRect& aRect) sl@0: { //currently only have 1 animation sl@0: if (iAnimUid==aUid) sl@0: iAnimPos = aRect; sl@0: } sl@0: sl@0: TRect* CCrpAnim::GetPosAnimation(const TUid& aUid) sl@0: { //currently only have 1 animation sl@0: if (iAnimUid==aUid) sl@0: return &iAnimPos; sl@0: else sl@0: return NULL; sl@0: } sl@0: sl@0: TBool CCrpAnim::RemoveAnimation(TUid) sl@0: { sl@0: iAnimUid=TUid::Null(); sl@0: iAnimData.Stop(EFalse); sl@0: return ETrue; sl@0: } sl@0: sl@0: void CCrpAnim::DoDraw() sl@0: { sl@0: DoDraw(iBlankIt); sl@0: } sl@0: sl@0: inline void CCrpAnim::DoDraw(TBool aBlankIt) sl@0: { sl@0: __ASSERT_ALWAYS(iWinType!=EBlank,AutoPanic(EAutoPanicWindowType)); sl@0: iCtWin->Gc()->Activate(*Window()); sl@0: Draw(iCtWin->Gc(),Size(),iIsBase,iRect,aBlankIt,iRepeatDrawMax,iAlphaValue); sl@0: if (iAnimUid!=TUid::Null()) sl@0: iCtWin->Gc()->DrawWsGraphic(iAnimUid,iAnimPos,iAnimData.Pckg()); sl@0: iCtWin->Gc()->Deactivate(); sl@0: } sl@0: sl@0: void CCrpAnim::DoDrawEllipse() sl@0: { sl@0: __ASSERT_ALWAYS(iWinType!=EBlank,AutoPanic(EAutoPanicWindowType)); sl@0: iCtWin->Gc()->Activate(*Window()); sl@0: DrawEllipse(iCtWin->Gc(),iRect,iAlphaValue); sl@0: iCtWin->Gc()->Deactivate(); sl@0: } sl@0: sl@0: void CCrpAnim::InvalidateAndRedraw(TBool /*aUseBlankItMember*/,TBool /*aBlankIt*/,TBool aUseRWindowInvalidate,TRect* aRect) sl@0: { sl@0: RWindow& win = *Window(); sl@0: if (aRect) sl@0: { sl@0: if (aUseRWindowInvalidate) sl@0: win.Invalidate(*aRect); sl@0: else sl@0: Invalidate(*aRect); sl@0: } sl@0: else sl@0: { sl@0: if (aUseRWindowInvalidate) sl@0: win.Invalidate(); sl@0: else sl@0: Invalidate(); sl@0: } sl@0: if (aRect) sl@0: win.BeginRedraw(*aRect); sl@0: else sl@0: win.BeginRedraw(); sl@0: DoDraw(); sl@0: win.EndRedraw(); sl@0: TheClient->Flush(); sl@0: } sl@0: sl@0: void CCrpAnim::Invalidate(const TRect &aRect) sl@0: { sl@0: TRect rect(aRect); sl@0: rect.Move(iCtWin->Position()); sl@0: CTUser::Splat(TheClient,rect,TRgb::Gray256(0)); sl@0: } sl@0: sl@0: // sl@0: } //end anonymous namespace sl@0: // sl@0: __WS_CONSTRUCT_STEP__(CrpAnim)