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