1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/graphics/windowing/windowserver/test/tauto/tcrpanim.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1464 @@
1.4 +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// Implements CTCrpAnim
1.18 +// Test CRP animations & their interaction with overlapping transparent/non-transparent windows
1.19 +// & wserv's underlying redraw-store strategies
1.20 +//
1.21 +//
1.22 +
1.23 +/**
1.24 + @file
1.25 + @test
1.26 + @internalComponent - Internal Symbian test code
1.27 +*/
1.28 +
1.29 +#include <w32stdgraphic.h>
1.30 +#include "tcrpanim.h"
1.31 +
1.32 +// RUN_SAMPLE_ON_LEFT allows the demo animation to run in the left-hand window during testing.
1.33 +// Used for demonstration purposes only
1.34 +#define RUN_SAMPLE_ON_LEFT
1.35 +
1.36 +namespace //anonymous local scope
1.37 + {
1.38 + const TInt KAnimationFrameDelayTime = 50000; // delay in microseconds between frames
1.39 + const TInt KShortDelayLoop = 2*KAnimationFrameDelayTime; // delay time in microseconds used in test cases
1.40 + const TInt KAnimationTotalFrames = 40; // total number of frames in a CWsGraphicBitmapAnimation
1.41 + const TInt KAnimDimension = 40; // animation width/height. We're enforcing a square animation here
1.42 + const TInt KFrameMissedAnimationsThreshold = 10; // maximum number of missed frame steps allowed
1.43 + const TInt KAnimationTearWidthThreshold = 4; // maximum columns permitted between a tear
1.44 + const TInt KMinGoodFrameThreshold = 30; // percentage threshold for number of good frames detected in a test
1.45 + const TInt KMaxXY = 200; // arbitrary maximum size of square used to invalidate a window
1.46 + const TInt KMaxRepeatDraw = 2; // arbitrary value for DrawLine calls during a Draw
1.47 + TUid KUidTestAnimation2 = {0xBAADF00D}; // unique id. for CWsGraphicBitmapAnimation object
1.48 + const TUint32 KWhitePixels = 0xFFFFFFFF; // 32-bit mask value for rgb white
1.49 + const TUint32 KBlackPixels = 0x00000000; // 32-bit value for rgb black
1.50 + const TPoint KPointZero(0,0); // initial point used for animation creation & manipulation (currently 0,0)
1.51 + const TPoint KPointOffsite(1000,1000); // point used to draw off-screen
1.52 + const TDisplayMode KTestDisplayMode = EColor16MU; // display mode used for testing
1.53 + const TInt KFrameStepCalculation = Max(1, KAnimDimension/Max(1, KAnimationTotalFrames)); // determine framestep size in columns
1.54 +
1.55 + enum TColorDetected
1.56 + {
1.57 + ECantTell=0,
1.58 + EDetRed=1,
1.59 + EDetGreen=2,
1.60 + EDetBlue=4,
1.61 + EDetBlack=0x10,
1.62 + EDetGrey=0x20,
1.63 + EDetWhite=0x40
1.64 + };
1.65 +
1.66 + class CCrpAnim;
1.67 + class CAnimRedrawWindow : public CTWin
1.68 + {
1.69 + public:
1.70 + CAnimRedrawWindow(CCrpAnim *aAnimWindow, TBool aIsBase);
1.71 + ~CAnimRedrawWindow();
1.72 + void Draw();
1.73 + private:
1.74 + CCrpAnim *iAnimWindow;
1.75 + TBool iIsBase;
1.76 + };
1.77 +
1.78 + class CCrpAnim : public CBase
1.79 + {
1.80 + friend class CAnimRedrawWindow;
1.81 + public:
1.82 + enum TWinType
1.83 + {
1.84 + ERedraw,
1.85 + EBlank, // note: not currently used in tcrpanim tests
1.86 + EBackedUp // note: not currently used in tcrpanim tests
1.87 + };
1.88 + public:
1.89 + CCrpAnim(TBool aIsBase, TWinType aWinType);
1.90 + ~CCrpAnim();
1.91 + enum
1.92 + {
1.93 + ENoTransparency=0x100
1.94 + };
1.95 + void ConstructL(const TPoint &aPos, const TSize &aSize,const TInt aAlphaValue=ENoTransparency);
1.96 + void DoDraw(TBool aBlankIt);
1.97 + inline void DoDraw();
1.98 + void DoDrawEllipse();
1.99 + inline TSize Size() {return iCtWin->Size();};
1.100 + inline RWindowBase* BaseWin() const {return iCtWin->BaseWin();};
1.101 + inline RWindow* Window() const {return STATIC_CAST(RWindow*, iCtWin->BaseWin());};
1.102 + inline CTBaseWin* CtBaseWin() {return iCtWin;};
1.103 + inline void Invalidate() {CTUser::Splat(TheClient, TRect(iCtWin->Position(), iCtWin->Size()), KRgbGray);};
1.104 + void Invalidate(const TRect &aRect);
1.105 + static void SetEllipseDrawMode(CGraphicsContext::TDrawMode aEllipseDrawMode);
1.106 + void InvalidateAndRedraw(TBool aUseBlankItMember,TBool aBlankIt,TBool aUseRWindowInvalidate,TRect* aRect=NULL);
1.107 +
1.108 + //A bit of an animation interface...
1.109 + //I have written this interface to be amenable to playing multiple animations,
1.110 + //which I think needs testing,
1.111 + //but the underlying implementation assumes one animation at present.
1.112 + //Your mission, should you choose to accept it, ....
1.113 +
1.114 + void SetPosAnimation(const TUid& aUid, const TRect& aRect);
1.115 + TRect* GetPosAnimation(const TUid& aUid);
1.116 + TWsGraphicAnimation* SetAnimation(TUid);
1.117 + TWsGraphicAnimation* GetAnimation(TUid);
1.118 + TBool RemoveAnimation(TUid);
1.119 + inline void SetBlankIt(TBool aNewVal) {iBlankIt = aNewVal;};
1.120 + inline void SetRepeatDrawMax(TInt aVal) {iRepeatDrawMax = aVal;};
1.121 + protected:
1.122 + static void Draw(CBitmapContext *aGc, const TSize &aSize, TBool aIsBase,const TRect &aRect, TBool aBlankIt,TInt aRepeat, TInt aAlphaValue);
1.123 + static void DrawEllipse(CBitmapContext *aGc, const TRect &aRect, TInt aAlphaValue);
1.124 + CTBaseWin *iCtWin;
1.125 + TWinType iWinType;
1.126 + TBool iIsBase;
1.127 + TBool iBlankIt;
1.128 + TRect iRect;
1.129 + TInt iRepeatDrawMax;
1.130 + static CGraphicsContext::TDrawMode iEllipseDrawMode;
1.131 + TUid iAnimUid;
1.132 + TWsGraphicAnimation iAnimData;
1.133 + TRect iAnimPos;
1.134 + TInt iAlphaValue;
1.135 + };
1.136 +
1.137 +/* Using this time delay class in order to allow animations to play in our draw.
1.138 + User::Wait does not allow the draw to occur (aparrently)
1.139 + Note when using this time-delay class: because other active objects can perform part of their
1.140 + processing whilst we wait, wrapping calls to this in __UHEAP_MARK / __UHEAP_MARKEND
1.141 + is likely to fail. The data providers and animators are a major cause of this.
1.142 +*/
1.143 + class CActiveWait : public CActive
1.144 + {
1.145 + public:
1.146 + static CActiveWait* NewL();
1.147 + ~CActiveWait();
1.148 + void Wait(TInt aDelay);
1.149 + // From CActive:
1.150 + void RunL();
1.151 + void DoCancel();
1.152 + TInt RunError(TInt aError);
1.153 + protected:
1.154 + CActiveWait();
1.155 + void ConstructL();
1.156 + protected:
1.157 + RTimer iTimer;
1.158 + TTime iFromTime;
1.159 + };
1.160 +
1.161 + CActiveWait* CActiveWait::NewL()
1.162 + {
1.163 + CActiveWait* self = new (ELeave) CActiveWait;
1.164 + CleanupStack::PushL(self);
1.165 + self->ConstructL();
1.166 + CleanupStack::Pop(self);
1.167 + return self;
1.168 + }
1.169 +
1.170 + void CActiveWait::ConstructL()
1.171 + {
1.172 + User::LeaveIfError(iTimer.CreateLocal());
1.173 + CActiveScheduler::Add(this);
1.174 + }
1.175 +
1.176 + CActiveWait::CActiveWait() : CActive(EPriorityNormal)
1.177 + {
1.178 + iFromTime.HomeTime();
1.179 + }
1.180 +
1.181 + CActiveWait::~CActiveWait()
1.182 + {
1.183 + Cancel();
1.184 + iTimer.Close();
1.185 + }
1.186 +
1.187 + void CActiveWait::DoCancel()
1.188 + {
1.189 + iTimer.Cancel();
1.190 + CActiveScheduler::Stop();
1.191 + }
1.192 +
1.193 + void CActiveWait::RunL()
1.194 + {
1.195 + CActiveScheduler::Stop();
1.196 + }
1.197 +
1.198 + TInt CActiveWait::RunError(TInt aError)
1.199 + {
1.200 + return aError; // exists so a break point can be placed on it.
1.201 + }
1.202 +
1.203 +/* Note when using this : because other active objects can perform part of their
1.204 + processing whilst we wait, wrapping calls to this in __UHEAP_MARK / __UHEAP_MARKEND
1.205 + is likely to fail. The data providers and animators are a major cause of this.
1.206 +*/
1.207 + void CActiveWait::Wait(TInt aDelay)
1.208 + {
1.209 + iTimer.After(iStatus, aDelay);
1.210 + SetActive();
1.211 + CActiveScheduler::Start();
1.212 + }
1.213 + CGraphicsContext::TDrawMode CCrpAnim::iEllipseDrawMode;
1.214 +
1.215 +//
1.216 + } //end anonymous local scope
1.217 +//
1.218 +
1.219 +/** This fn allocates an animation frame of the specified dimensions.
1.220 + Not tested outside the current limited parameter set (16/2/2007).
1.221 + Note the use of 32-bit integers for pixel/colour values. Using display mode lower than 24bpp may not produce correct results
1.222 + My attempt to write animation generating code that avoids CIclLoader and Decoder class.
1.223 + @param aDelayUs the display time for the frame
1.224 + @param aImageType Colour format for colour plane. 24MA currently not flagged correctly I expect.
1.225 + @param aMaskType Format for mask. ENone for no mask.
1.226 + @param aImageSize Width/height of bitmap area
1.227 + @param aImageOffset Optional offset for bitmap area
1.228 + @param aTotalSize Optional width/height of whole animation (I think)
1.229 + @return CFrame filled in with allocated bitmaps. The get methods for the bitmaps return const type.
1.230 +**/
1.231 +static CWsGraphicBitmapAnimation::CFrame* NewFrameLC(TInt aDelayUs,TDisplayMode aImageType,TDisplayMode aMaskType,const TSize& aImageSize,const TPoint& aImageOffset=KPointZero,const TSize& aTotalSize=TSize(0,0))
1.232 + {
1.233 + TFrameInfo info;
1.234 + info.iFrameCoordsInPixels = TRect(aImageOffset,aImageSize);
1.235 + info.iFrameSizeInTwips = aImageSize; //this is zero in the gif loader
1.236 + info.iDelay = TTimeIntervalMicroSeconds(aDelayUs);
1.237 + info.iFlags = TFrameInfo::EColor|TFrameInfo::ELeaveInPlace|TFrameInfo::EUsesFrameSizeInPixels;
1.238 + if (aMaskType != ENone)
1.239 + {
1.240 + info.iFlags|=TFrameInfo::ETransparencyPossible;
1.241 + }
1.242 + if ((aTotalSize.iHeight > 0) && (aTotalSize.iWidth > 0))
1.243 + {
1.244 + // restrict the size of the frame to specified size of the animation
1.245 + info.iOverallSizeInPixels = aTotalSize;
1.246 + }
1.247 + else
1.248 + {
1.249 + // assign the size of the frame to the size of the entire bitmap area
1.250 + info.iOverallSizeInPixels = info.iFrameCoordsInPixels.iBr.AsSize();
1.251 + }
1.252 + info.iFrameDisplayMode = aImageType;
1.253 + info.iBackgroundColor = KRgbGreen;
1.254 +
1.255 + CWsGraphicBitmapAnimation::CFrame* frame = CWsGraphicBitmapAnimation::CFrame::NewL();
1.256 + CleanupStack::PushL(frame);
1.257 + frame->SetFrameInfo(info);
1.258 + CFbsBitmap* bitmap = new(ELeave) CFbsBitmap;
1.259 + frame->SetBitmap(bitmap); //takes ownership
1.260 + TSize frameInfoSize = info.iFrameCoordsInPixels.Size();
1.261 + User::LeaveIfError(bitmap->Create(frameInfoSize, aImageType));
1.262 + if((TFrameInfo::EAlphaChannel|TFrameInfo::ETransparencyPossible) & info.iFlags)
1.263 + {
1.264 + CFbsBitmap* mask = new(ELeave) CFbsBitmap;
1.265 + frame->SetMask(mask); //takes ownership
1.266 + User::LeaveIfError(mask->Create(frameInfoSize, aMaskType));
1.267 + }
1.268 + return frame;
1.269 + }
1.270 +
1.271 +//
1.272 +// function called back by TCleanupItem frameListCleanup from within CreateAnimFramesL(..) method
1.273 +//
1.274 +void CleanupFrameList(TAny* aPtr)
1.275 + {
1.276 + RPointerArray<CWsGraphicBitmapAnimation::CFrame>* ptrArray = STATIC_CAST(RPointerArray<CWsGraphicBitmapAnimation::CFrame>*, aPtr);
1.277 + ptrArray->ResetAndDestroy();
1.278 + ptrArray->Close();
1.279 + }
1.280 +
1.281 +/** Helper function for making animation frames.
1.282 + //Called from CreateAnimL(...)
1.283 + @param aDelayUs the delay between frames
1.284 + @param aNumFrames number of frames (approx - image width is a factor)
1.285 + @param aImageType colour format of colour data. This may not work properly for non-32-bit, but I haven't fully understood TBitmapUtil documentation.
1.286 + @param aMaskType format for mask - ENone for no mask.
1.287 + @param aImageSize width/height of animation
1.288 + @param aBgCol background colour for image non-masked areas. Masked areas are black.
1.289 + @param aFgCol foreground colour of animating area
1.290 + @param aFrames frames that the animation is constructed from
1.291 +**/
1.292 +static void CreateAnimFramesL(TInt aDelayUs,TInt aNumFrames,TDisplayMode aImageType,TDisplayMode aMaskType,TSize aImageSize,TRgb aBgCol,TRgb aFgCol, RPointerArray<CWsGraphicBitmapAnimation::CFrame>& aFrames)
1.293 + {
1.294 + const TInt animWH = aImageSize.iWidth;
1.295 + const TInt animStep = Max(1,animWH/Max(1,aNumFrames)); //note this intentionally rounds down to avoid overflows
1.296 + for (TInt ii = 0 ; ii < animWH ; ii += animStep)
1.297 + {
1.298 + CWsGraphicBitmapAnimation::CFrame* frame = NewFrameLC(aDelayUs,aImageType,aMaskType,aImageSize,KPointZero,aImageSize);
1.299 + aFrames.AppendL(frame);
1.300 + CleanupStack::Pop(frame);
1.301 + TBitmapUtil utilMask(CONST_CAST(CFbsBitmap*, frame->Mask()));
1.302 + TBitmapUtil utilCol(CONST_CAST(CFbsBitmap*, frame->Bitmap()));
1.303 + utilCol.Begin(KPointZero);
1.304 +
1.305 + // cycle through the frame's actual bitmap & assign each pixel a value identical to the specified colours
1.306 + TUint32 colback=aBgCol.Internal();
1.307 + TUint32 colfront=aFgCol.Internal();
1.308 + TInt row = KErrNone;
1.309 + TInt col = KErrNone;
1.310 + for (row = 0 ; row < aImageSize.iHeight ; row++)
1.311 + {
1.312 + utilCol.SetPos(TPoint(0, row));
1.313 + for (col = 0 ; col < aImageSize.iWidth ; col++)
1.314 + {
1.315 + utilCol.SetPixel(colback);
1.316 + utilCol.IncXPos();
1.317 + }
1.318 + utilCol.SetPos(TPoint(ii, row));
1.319 + for (col = 0 ; col < animStep ; col++) //Note I rely on intentional rounding down here!
1.320 + {
1.321 + utilCol.SetPixel(colfront);
1.322 + utilCol.IncXPos();
1.323 + }
1.324 + }
1.325 +
1.326 + if (aMaskType)
1.327 + {
1.328 + // cycle through each pixel of the frame's mask & assign a default pixel a colour value
1.329 + utilMask.Begin(KPointZero);
1.330 + for (row = 0 ; row < aImageSize.iHeight ; row++)
1.331 + {
1.332 + utilMask.SetPos(TPoint(0,row));
1.333 + for (col = 0 ; col < aImageSize.iWidth ; col++)
1.334 + {
1.335 + utilMask.SetPixel(KWhitePixels);
1.336 + utilMask.IncXPos();
1.337 + }
1.338 + }
1.339 +
1.340 + const TInt maxmaskWidth = Min(8,Max(animWH/3,2));
1.341 +
1.342 + //cut the corners off the mask
1.343 + for (row = 0 ; row < maxmaskWidth ; row++)
1.344 + {
1.345 + TInt currentX = maxmaskWidth - row;
1.346 + TInt xPos = KErrNone;
1.347 +
1.348 + utilCol.SetPos(TPoint(0,row));
1.349 + utilMask.SetPos(TPoint(0,row));
1.350 + for(xPos = currentX ; xPos >= 0 ; xPos--)
1.351 + {
1.352 + utilCol.SetPixel(KBlackPixels);
1.353 + utilCol.IncXPos();
1.354 + utilMask.SetPixel(KBlackPixels);
1.355 + utilMask.IncXPos();
1.356 + }
1.357 +
1.358 + utilCol.SetPos(TPoint(animWH - 1, row));
1.359 + utilMask.SetPos(TPoint(animWH - 1, row));
1.360 + for(xPos = currentX ; xPos >= 0 ; xPos--)
1.361 + {
1.362 + utilCol.SetPixel(KBlackPixels);
1.363 + utilCol.DecXPos();
1.364 + utilMask.SetPixel(KBlackPixels);
1.365 + utilMask.DecXPos();
1.366 + }
1.367 +
1.368 + utilCol.SetPos(TPoint(0, animWH - 1 - row));
1.369 + utilMask.SetPos(TPoint(0, animWH - 1 - row));
1.370 + for(xPos = currentX ; xPos >= 0 ; xPos--)
1.371 + {
1.372 + utilCol.SetPixel(KBlackPixels);
1.373 + utilCol.IncXPos();
1.374 + utilMask.SetPixel(KBlackPixels);
1.375 + utilMask.IncXPos();
1.376 + }
1.377 +
1.378 + utilCol.SetPos(TPoint(animWH - 1, animWH - 1 - row));
1.379 + utilMask.SetPos(TPoint(animWH - 1, animWH - 1 - row));
1.380 + for(xPos = currentX ; xPos >= 0 ; xPos--)
1.381 + {
1.382 + utilCol.SetPixel(KBlackPixels);
1.383 + utilCol.DecXPos();
1.384 + utilMask.SetPixel(KBlackPixels);
1.385 + utilMask.DecXPos();
1.386 + }
1.387 + }
1.388 + utilMask.End();
1.389 + }
1.390 + utilCol.End();
1.391 + }
1.392 + }
1.393 +
1.394 +/** My attempt to write animation generating code that avoids CIclLoader and Decoder class.
1.395 + //It is better if this test class used it's own generated animation
1.396 + //rather than relying on the GIF loader in order to reduce the cross-dependencies.
1.397 + //The animation generated is a simple vertical line moving from left to right.
1.398 + //To prove the masking, I cut the corners off.
1.399 + @param aDelayUs the delay between frames
1.400 + @param aNumFrames number of frames (approx - image width is a factor)
1.401 + @param aImageType colour format of colour data. This may not work properly for non-32-bit, but I haven't fully understood TBitmapUtil documentation.
1.402 + @param aMaskType format for mask - ENone for no mask.
1.403 + @param aImageSize width/height of animation
1.404 + @param aBgCol background colour for image non-masked areas. Masked areas are black.
1.405 + @param aFgCol foreground colour of animating area
1.406 + @param aTUid TUid assigned to animation
1.407 + @return CWsGraphicBitmapAnimation allocated to represent the final animation
1.408 +**/
1.409 +static CWsGraphicBitmapAnimation* CreateAnimL(TInt aDelayUs,TInt aNumFrames,TDisplayMode aImageType,TDisplayMode aMaskType,TSize aImageSize,TRgb aBgCol,TRgb aFgCol,TUid& aTUid)
1.410 + {
1.411 + RPointerArray<CWsGraphicBitmapAnimation::CFrame> frames;
1.412 + TCleanupItem frameListCleanup(CleanupFrameList, &frames);
1.413 + CleanupStack::PushL(frameListCleanup);
1.414 +
1.415 + CreateAnimFramesL(aDelayUs, aNumFrames, aImageType, aMaskType, aImageSize,aBgCol, aFgCol, frames);
1.416 +
1.417 + CWsGraphicBitmapAnimation* anim = CWsGraphicBitmapAnimation::NewL(aTUid,frames.Array());
1.418 + CleanupStack::PopAndDestroy(&frames);
1.419 + return anim;
1.420 + }
1.421 +
1.422 +//
1.423 +// Describes the pure colour of the RGB value. yellow/magenta/cyan set 2 bits. White/grey is seperately flagged.
1.424 +// This method attempts to determine the strongest primary colour present in any given pixel.
1.425 +// Note: The algorithm used is known to work for the current test cases only but requires careful review
1.426 +// for anyone making additional changes to tcrpanim. Given time, improved algorithm should be developed
1.427 +// to replace the current one
1.428 +//
1.429 +TUint PredominantColour(TUint aCol)
1.430 + { //I don't like all these ifs, but I don't see an easy alternative
1.431 + //Possibly a bit look-up of the deltas from average would work
1.432 + //(ignoring the bottom 5 bits =32, not 0x30=48. Ignore bottom 4 bits and accept 3-same answers, or divide by delta?)
1.433 + //
1.434 + const TInt Kdelta=0x30;
1.435 + TInt red=(aCol&0x00ff0000)>>16;
1.436 + TInt green=(aCol&0x0000ff00)>>8;
1.437 + TInt blue=(aCol&0x000000ff);
1.438 + TInt ave=((red+green+blue)*(65536/3))>>16;
1.439 + TBool rOverA=(red>ave);
1.440 + TBool gOverA=(green>ave);
1.441 + TBool bOverA=(blue>ave);
1.442 + TInt numOverAve=(rOverA?1:0)+(gOverA?1:0)+(bOverA?1:0);
1.443 +
1.444 + if (numOverAve==1)
1.445 + {
1.446 + if (rOverA)
1.447 + {
1.448 + if (red>ave+Kdelta)
1.449 + {
1.450 + if ((green-blue)>-Kdelta && (green-blue)<Kdelta)
1.451 + return EDetRed;
1.452 + }
1.453 + else
1.454 + {
1.455 + if (ave<Kdelta)
1.456 + return EDetBlack;
1.457 + else
1.458 + {
1.459 + if (green>ave-Kdelta && blue>ave-Kdelta)
1.460 + {
1.461 + if (ave>256-Kdelta)
1.462 + return EDetWhite;
1.463 + else
1.464 + return EDetGrey;
1.465 + }
1.466 + }
1.467 + }
1.468 + }
1.469 +
1.470 + if (gOverA)
1.471 + {
1.472 + if (green>ave+Kdelta)
1.473 + {
1.474 + if ((blue-red)>-Kdelta && (blue-red)<Kdelta)
1.475 + return EDetGreen;
1.476 + }
1.477 + else
1.478 + {
1.479 + if (ave<Kdelta)
1.480 + return EDetBlack;
1.481 + else
1.482 + {
1.483 + if (red>ave-Kdelta && blue>ave-Kdelta)
1.484 + if (ave>256-Kdelta)
1.485 + return EDetWhite;
1.486 + else
1.487 + return EDetGrey;
1.488 + }
1.489 + }
1.490 + }
1.491 +
1.492 + if (bOverA)
1.493 + {
1.494 + if (blue>ave+Kdelta)
1.495 + {
1.496 + if ((green-red)>-Kdelta && (green-red)<Kdelta)
1.497 + return EDetBlue;
1.498 + }
1.499 + else
1.500 + {
1.501 + if (ave<Kdelta)
1.502 + return EDetBlack;
1.503 + else
1.504 + {
1.505 + if (red>ave-Kdelta && green>ave-Kdelta)
1.506 + if (ave>256-Kdelta)
1.507 + return EDetWhite;
1.508 + else
1.509 + return EDetGrey;
1.510 + }
1.511 + }
1.512 + }
1.513 + }
1.514 + else
1.515 + {
1.516 + if (!rOverA)
1.517 + if (red<ave-Kdelta)
1.518 + {
1.519 + if ((green-blue)>-Kdelta && (green-blue)<Kdelta)
1.520 + return EDetGreen|EDetBlue;
1.521 + }
1.522 + else
1.523 + {
1.524 + if (ave>256-Kdelta)
1.525 + return EDetWhite;
1.526 + else
1.527 + {
1.528 + if (blue<ave+Kdelta && green<ave+Kdelta)
1.529 + {
1.530 + if (ave<Kdelta)
1.531 + return EDetBlack;
1.532 + else
1.533 + return EDetGrey;
1.534 + }
1.535 + }
1.536 + }
1.537 +
1.538 + if (!gOverA)
1.539 + {
1.540 + if (green<ave-Kdelta)
1.541 + {
1.542 + if ((blue-red)>-Kdelta && (blue-red)<Kdelta)
1.543 + return EDetRed|EDetBlue;
1.544 + }
1.545 + else
1.546 + {
1.547 + if (ave>256-Kdelta)
1.548 + return EDetWhite;
1.549 + else
1.550 + {
1.551 + if (blue<ave+Kdelta && red<ave+Kdelta)
1.552 + if (ave<Kdelta)
1.553 + return EDetBlack;
1.554 + else
1.555 + return EDetGrey;
1.556 + }
1.557 + }
1.558 + }
1.559 +
1.560 + if (!bOverA)
1.561 + {
1.562 + if (blue<ave-Kdelta)
1.563 + {
1.564 + if ((green-red)>-Kdelta && (green-red)<Kdelta)
1.565 + return EDetGreen|EDetRed;
1.566 + }
1.567 + else
1.568 + {
1.569 + if (ave>256-Kdelta)
1.570 + return EDetWhite;
1.571 + else
1.572 + {
1.573 + if (red<ave+Kdelta && green<ave+Kdelta)
1.574 + if (ave<Kdelta)
1.575 + return EDetBlack;
1.576 + else
1.577 + return EDetGrey;
1.578 + }
1.579 + }
1.580 + }
1.581 + }
1.582 + return ECantTell;
1.583 + }
1.584 +
1.585 +/**
1.586 + Helper fn to ensure I put the anims in the same place each time...
1.587 +**/
1.588 +void CalcCentredAnimPosition(TRect& aRect,const TSize& aWinSize)
1.589 + {
1.590 + aRect.Shrink(aWinSize.iWidth*3/8,aWinSize.iHeight*4/10);
1.591 + }
1.592 +
1.593 +CTCrpAnim::CTCrpAnim(CTestStep* aStep) :
1.594 + CTWsGraphicsBase(aStep)
1.595 + {
1.596 + }
1.597 +
1.598 +void CTCrpAnim::ConstructL()
1.599 + {
1.600 + TheClient->iGroup->WinTreeNode()->SetOrdinalPosition(0);
1.601 + iRedrawWin=new(ELeave) CCrpAnim(EFalse, CCrpAnim::ERedraw);
1.602 + iBaseWin=new(ELeave) CCrpAnim(EFalse, CCrpAnim::ERedraw);
1.603 + iOverWin=new(ELeave) CCrpAnim(EFalse, CCrpAnim::ERedraw);
1.604 +
1.605 + TSize screenSize=TheClient->iGroup->Size();
1.606 + TInt winWidth=(screenSize.iWidth/3)-10;
1.607 + TInt winHeight=screenSize.iHeight-10;
1.608 + TSize windowSize(winWidth,winHeight);
1.609 +
1.610 + iRedrawWin->ConstructL(TPoint(screenSize.iWidth/3*2+5,5), windowSize);
1.611 + iBaseWin->ConstructL(TPoint(screenSize.iWidth/3+5,5), windowSize);
1.612 +
1.613 + //Create a transparent window that exactly overlaps the test window
1.614 + //If transparency is not supported the leave causes the window to be destroyed and set to NULL.
1.615 + //There is a test for transparency supported, but that simply creates a temp window to test anyway...
1.616 +
1.617 + //Note that when I originally wrote this test to fix PDEF101991, it generated white areas that I detected.
1.618 + //However, if this transparent window used for extended tests is created over the test window,
1.619 + //that somehow stops the white fill from occurring.
1.620 + //The fault still occurs, but the previous screen contents are left behind.
1.621 + //So now this window is created at an off-screen location.
1.622 + TRAPD(err, iOverWin->ConstructL(KPointOffsite, windowSize, 0x80); iOverWin->SetBlankIt(ETrue); iOverWin->SetRepeatDrawMax(KMaxRepeatDraw););
1.623 + if (err)
1.624 + {
1.625 + delete iOverWin;
1.626 + iOverWin = NULL;
1.627 + }
1.628 +
1.629 + iTestWin = iRedrawWin;
1.630 + iTestWin->SetRepeatDrawMax(KMaxRepeatDraw);
1.631 + iBaseWin->SetRepeatDrawMax(KMaxRepeatDraw);
1.632 +
1.633 + // create animation object & share it with everyone
1.634 + iAnim = CreateAnimL(KAnimationFrameDelayTime,KAnimationTotalFrames,KTestDisplayMode,EGray256,TSize(KAnimDimension, KAnimDimension),KRgbBlue,KRgbRed,KUidTestAnimation2);
1.635 + if (!iAnim)
1.636 + {
1.637 + User::Leave(KErrNoMemory);
1.638 + }
1.639 + iAnim->ShareGlobally();
1.640 +
1.641 + // calculate minimum length of the red line
1.642 + 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
1.643 + iMinimumCalcRedLine = KAnimDimension - maxmaskHeight*2; // the height of the image minus the two cut corners
1.644 +
1.645 + // create the timer object
1.646 + iWaiter = CActiveWait::NewL();
1.647 +
1.648 + // create screen bitmap object & scanline buffer
1.649 + iScreenBitmap = new (ELeave) CFbsBitmap;
1.650 + User::LeaveIfError(iScreenBitmap->Create(TSize(KAnimDimension, KAnimDimension), KTestDisplayMode));
1.651 + TInt bufLength = iScreenBitmap->ScanLineLength(windowSize.iHeight, KTestDisplayMode);
1.652 + iScanlineBuf = HBufC8::NewL(bufLength);
1.653 +
1.654 + #ifdef RUN_SAMPLE_ON_LEFT
1.655 + {
1.656 + // play animation on iBaseWin window
1.657 + iBaseWin->SetAnimation(KUidTestAnimation2)->Play(ETrue);
1.658 + TSize subsize1 = iTestWin->BaseWin()->Size();
1.659 + TRect subposition1(subsize1);
1.660 + CalcCentredAnimPosition(subposition1, subsize1);
1.661 + iBaseWin->SetPosAnimation(KUidTestAnimation2, subposition1);
1.662 + iBaseWin->InvalidateAndRedraw(ETrue,EFalse,ETrue);
1.663 + }
1.664 + #endif
1.665 + }
1.666 +
1.667 +CTCrpAnim::~CTCrpAnim()
1.668 + {
1.669 + delete iRedrawWin;
1.670 + delete iBaseWin;
1.671 + delete iOverWin;
1.672 + if (iAnim)
1.673 + {
1.674 + // destroy the animation object
1.675 + iAnim->UnShareGlobally();
1.676 + iAnim->Destroy();
1.677 + delete iAnim;
1.678 + iAnim = NULL;
1.679 + }
1.680 + if (iWaiter)
1.681 + {
1.682 + // destroy the timer object
1.683 + delete iWaiter;
1.684 + iWaiter = NULL;
1.685 + }
1.686 + if (iScreenBitmap)
1.687 + {
1.688 + // destroy the screen capture of the animation
1.689 + delete iScreenBitmap;
1.690 + iScreenBitmap = NULL;
1.691 + }
1.692 + if (iScanlineBuf)
1.693 + {
1.694 + // destroy the scanline buffer
1.695 + delete iScanlineBuf;
1.696 + iScanlineBuf = NULL;
1.697 + }
1.698 + User::After(200000);
1.699 + }
1.700 +
1.701 +//
1.702 +// This method checks the animation contained in the aAnimWin window has progressed. That is
1.703 +// that it's drawn a sufficient number of concurrent frames to screen & the animation is
1.704 +// drawn properly to screen
1.705 +// returns a Bool identifying whether the animation is considered 'good' or not
1.706 +//
1.707 +void CTCrpAnim::CheckAnimProgressedL(CAnonAnimWindow* aAnimWin, TInt aAdditionalFrameCount, TBool aCaptureFrameResult)
1.708 + {
1.709 + TBool goodAnimation = ETrue;
1.710 +
1.711 + // retrieve the rect from the screen's bitmap that contains the animation
1.712 + CWsScreenDevice* screen = TheClient->iScreen;
1.713 + TRect animPos = *aAnimWin->GetPosAnimation(KUidTestAnimation2);
1.714 + CTBaseWin* bWin = aAnimWin->CtBaseWin();
1.715 + animPos.Move(bWin->Position());
1.716 + User::LeaveIfError(screen->CopyScreenToBitmap(iScreenBitmap, animPos));
1.717 +
1.718 + TInt frameNum = DetermineApproxFrameNum(iScreenBitmap, aCaptureFrameResult); // determines the frame Number & checks quality of animation (no tearing, etc)
1.719 + TBool frameIdentified=(frameNum>=0);
1.720 +
1.721 + if (aCaptureFrameResult)
1.722 + {
1.723 + if (frameIdentified)
1.724 + {
1.725 + if (iPreviousFrameNum != KErrNotFound)
1.726 + {
1.727 + if (iPreviousFrameNum < frameNum)
1.728 + {
1.729 + TInt frameStep = KFrameStepCalculation * aAdditionalFrameCount;
1.730 + iPreviousFrameNum += frameStep; // move to our *expected* framenumber
1.731 + if (frameNum > iPreviousFrameNum)
1.732 + {
1.733 + // the frame number is ahead of it's expected position
1.734 + // This suggests we've possibly missed animating a frame in wserv
1.735 + // or test code isn't getting a chance to execute as crp animations taking all cpu cycles
1.736 + // If its significantly outside norms, we log the fact (as a performance metric)
1.737 + TInt performance = ((frameNum - iPreviousFrameNum) / frameStep);
1.738 + if (performance > KFrameMissedAnimationsThreshold)
1.739 + {
1.740 + iFrameStatus.iFrameSkipped++;
1.741 + goodAnimation = EFalse;
1.742 + }
1.743 + }
1.744 + // else we're animating above an acceptable threshold
1.745 + }
1.746 + else if (iPreviousFrameNum == frameNum) // potentially not animating anymore
1.747 + {
1.748 + iFrameStatus.iFrameIdentical++;
1.749 + goodAnimation = EFalse;
1.750 + }
1.751 + // else animation is progressing fine
1.752 + }
1.753 + // ignore iPreviousFrameNum == KErrNotFound
1.754 + }
1.755 + else
1.756 + {
1.757 + goodAnimation = EFalse; // couldn't id the red line
1.758 + }
1.759 +
1.760 + if (goodAnimation)
1.761 + {
1.762 + iFrameStatus.iFrameOK++;
1.763 + }
1.764 + }
1.765 + // else we were only interested in calculating the frameNum
1.766 + iPreviousFrameNum = frameNum;
1.767 + }
1.768 +
1.769 +//
1.770 +// method to estimate the framenumber based on the location of the thin, red line.
1.771 +// Also checks whether tearing of the animation has occured or the animation
1.772 +// is only partially drawn.
1.773 +// These are known issues with wserv animation performance & so we give some allowance for error
1.774 +//
1.775 +TInt CTCrpAnim::DetermineApproxFrameNum(CFbsBitmap* aBitmap, TBool aCaptureFrameResult)
1.776 + {
1.777 + TInt colFirstTear = KErrNotFound; // column id'ing the first tear in the vertical line
1.778 + TPtr8 des = iScanlineBuf->Des(); // ptr to the scanline buffer
1.779 +
1.780 + // locate the thin, red line in the bitmap
1.781 + for (TInt xPos = 0 ; xPos < aBitmap->SizeInPixels().iWidth ; xPos++)
1.782 + {
1.783 + aBitmap->GetVerticalScanLine(des, xPos, EColor16MA);
1.784 + TUint32* pixel = (TUint32*) des.Ptr();
1.785 + TInt colour = KErrNone;
1.786 +
1.787 + for (TInt ii = 0 ; ii < aBitmap->SizeInPixels().iHeight ; ii++)
1.788 + {
1.789 + colour = PredominantColour(*pixel);
1.790 + if (colour & EDetRed)
1.791 + {
1.792 + if (colFirstTear < 0)
1.793 + {
1.794 + // check the length of the red line is a good length
1.795 + pixel += (iMinimumCalcRedLine - 1); // minus the one pixel to position on last pixel in red line
1.796 + colour = PredominantColour(*pixel);
1.797 + if (colour & EDetRed)
1.798 + {
1.799 + // good line
1.800 + return xPos;
1.801 + }
1.802 + else // we've detected first part of a torn line
1.803 + {
1.804 + colFirstTear = xPos;
1.805 + }
1.806 + }
1.807 + else
1.808 + {
1.809 + // located second part of torn line
1.810 + if ((xPos - colFirstTear) > KAnimationTearWidthThreshold)
1.811 + {
1.812 + if (aCaptureFrameResult)
1.813 + {
1.814 + iFrameStatus.iFrameTearing++;
1.815 + }
1.816 + xPos = KErrNotFound;
1.817 + }
1.818 + return xPos;
1.819 + }
1.820 + break;
1.821 + }
1.822 + pixel++;
1.823 + }
1.824 + }
1.825 + if (aCaptureFrameResult)
1.826 + {
1.827 + if (colFirstTear < 0)
1.828 + {
1.829 + iFrameStatus.iFrameEmpty++; // we never located any red line at all
1.830 + }
1.831 + else
1.832 + {
1.833 + iFrameStatus.iFramePartial++; // we only located a single, small part of the red line
1.834 + }
1.835 + }
1.836 + return KErrNotFound;
1.837 + }
1.838 +
1.839 +/** This internal loop tests that the animation and the foreground interact correctly
1.840 + The primary test is that the outline of the animation
1.841 + intersects the lines drawn on the foreground correctly, compared to a reference version.
1.842 + The iBaseWin is already showing this reference anim.
1.843 + If the animation is not drawn, or the foreground is wiped, then this test will fail.
1.844 +**/
1.845 +void CTCrpAnim::TestSpriteLoopL(TBool aAnimForeground,TBool aDrawForeground)
1.846 + {
1.847 + _LIT(KForegroundInfo,"TestSpriteLoop animForeground [%d] drawForeground [%d]");
1.848 + INFO_PRINTF3(KForegroundInfo, aAnimForeground, aDrawForeground);
1.849 +
1.850 + if (!iOverWin && (aAnimForeground || aDrawForeground))
1.851 + {
1.852 + User::Leave(KErrGeneral); // unable to run this test without iOverWin
1.853 + }
1.854 +
1.855 + ResetFrameCounters();
1.856 + iTestWin->RemoveAnimation(KUidTestAnimation2);
1.857 + iTestWin->SetBlankIt(ETrue);
1.858 + if (iOverWin)
1.859 + {
1.860 + iOverWin->RemoveAnimation(KUidTestAnimation2);
1.861 + iOverWin->SetBlankIt(ETrue);
1.862 + }
1.863 +
1.864 + // determine which window holds the animation, & which will be invalidated with progressively larger rects
1.865 + CCrpAnim* animWin=aAnimForeground?iOverWin:iTestWin;
1.866 + CCrpAnim* paintWin=aDrawForeground?iOverWin:iTestWin;
1.867 + paintWin->SetBlankIt(EFalse);
1.868 +
1.869 + // set & play the animation on the specified window (animWin)
1.870 + animWin->SetAnimation(KUidTestAnimation2)->Play(ETrue);
1.871 + TSize subsize1 = paintWin->BaseWin()->Size();
1.872 + TRect subposition1(subsize1);
1.873 + CalcCentredAnimPosition(subposition1, subsize1);
1.874 + animWin->SetPosAnimation(KUidTestAnimation2, subposition1);
1.875 +
1.876 + #ifdef RUN_SAMPLE_ON_LEFT
1.877 + // play the demo animation in the left-hand window also
1.878 + iBaseWin->InvalidateAndRedraw(ETrue, EFalse, ETrue);
1.879 + #endif
1.880 +
1.881 + iTestWin->InvalidateAndRedraw(ETrue,EFalse,ETrue);
1.882 + if (iOverWin)
1.883 + {
1.884 + iOverWin->InvalidateAndRedraw(ETrue,EFalse,ETrue);
1.885 + }
1.886 +
1.887 + // invalidate increasingly larger squares on paintWin
1.888 + // note, some fully overlap the animation, some partially overlap, and some don't overlap at all
1.889 + TInt invalidateWaitTime=KAnimationFrameDelayTime*3/4; // microseconds
1.890 + TInt temp = KErrNotFound;
1.891 + for (TInt step=30;step<KMaxXY;step+=30)
1.892 + {
1.893 + for (TInt xx=0;xx<KMaxXY;xx+=step)
1.894 + {
1.895 + for (TInt yy=10;yy<KMaxXY;yy+=step)
1.896 + {
1.897 + // calculate rectangle & invalidate paintWin with it
1.898 + TRect invalidRect(xx,yy,xx+step,yy+step);
1.899 + paintWin->InvalidateAndRedraw(ETrue,EFalse,ETrue,&invalidRect);
1.900 +
1.901 + // calculate any additional frames that may be drawn by above. Note intentionally ignore frame result
1.902 + temp = iPreviousFrameNum;
1.903 + CheckAnimProgressedL(animWin, 1, EFalse);
1.904 +
1.905 + //new defect DEF101896: Test runs faster with this line removed, but there is evident tearing
1.906 + iWaiter->Wait(invalidateWaitTime); //DEF101896 search string: //interrupt_foreground_draw
1.907 +
1.908 + if (temp == iPreviousFrameNum)
1.909 + {
1.910 + // give wserv more time to animate the frame
1.911 + iWaiter->Wait(invalidateWaitTime);
1.912 + }
1.913 + CheckAnimProgressedL(animWin, 1); // calculate the frame drawn. Capture frame result
1.914 + }
1.915 + }
1.916 + }
1.917 +
1.918 + // determine whether the animation was successful (ie: enough Good frames were detected) or not
1.919 + // Note KMinGoodFrameThreshold is essentially an arbitrary number. This can be adjusted to accommodate
1.920 + // performance requirements as needed
1.921 + temp = LogResults();
1.922 + TInt quality = 100*iFrameStatus.iFrameOK/temp;
1.923 + TEST(quality > KMinGoodFrameThreshold);
1.924 +
1.925 + ResetFrameCounters();
1.926 + iWaiter->Cancel();
1.927 + iTestWin->RemoveAnimation(KUidTestAnimation2);
1.928 + iTestWin->SetBlankIt(ETrue);
1.929 + if (iOverWin)
1.930 + {
1.931 + iOverWin->RemoveAnimation(KUidTestAnimation2);
1.932 + iOverWin->SetBlankIt(ETrue);
1.933 + }
1.934 + }
1.935 +
1.936 +//
1.937 +// resets the frame trackers to intial values
1.938 +//
1.939 +void CTCrpAnim::ResetFrameCounters()
1.940 + {
1.941 + iPreviousFrameNum = KErrNotFound;
1.942 + iFrameStatus.iFrameOK = 0;
1.943 + iFrameStatus.iFramePartial = 0;
1.944 + iFrameStatus.iFrameIdentical = 0;
1.945 + iFrameStatus.iFrameEmpty = 0;
1.946 + iFrameStatus.iFrameTearing = 0;
1.947 + iFrameStatus.iFrameSkipped = 0;
1.948 + }
1.949 +
1.950 +//
1.951 +// Log the current frame results & return the total number of frame calculations
1.952 +//
1.953 +// Calculated : the total number of frame-checks run
1.954 +// Good: the frame was successfully drawn to screen & within specified tolerances for tearing, expected position & colour
1.955 +// Partial: the frame was only partially drawn to screen. Specifcally the animated red line was only partially drawn
1.956 +// Identical: the frame was in the same position as the last frame
1.957 +// Empty: no redline was detected at all in the frame
1.958 +// Skipped: the position of the frame was beyond the expected position
1.959 +//
1.960 +// There is a dependency on the timing as to when the frame is animated hence tolerances are used to allow
1.961 +// for this.
1.962 +//
1.963 +TInt CTCrpAnim::LogResults()
1.964 + {
1.965 + TInt result = iFrameStatus.iFrameOK + iFrameStatus.iFramePartial + iFrameStatus.iFrameIdentical +
1.966 + iFrameStatus.iFrameEmpty + iFrameStatus.iFrameTearing + iFrameStatus.iFrameSkipped;
1.967 + INFO_PRINTF4(_L("\tAnimation results: Calculated[%d], Good[%d], Partial[%d]"), result, iFrameStatus.iFrameOK, iFrameStatus.iFramePartial);
1.968 + INFO_PRINTF5(_L("\tAnimation results: Identical[%d], Empty[%d], Tearing[%d], Skipped[%d]"), iFrameStatus.iFrameIdentical, iFrameStatus.iFrameEmpty, iFrameStatus.iFrameTearing, iFrameStatus.iFrameSkipped);
1.969 + return result;
1.970 + }
1.971 +
1.972 +/** This test tests the result of drawing an animation and main draw to two windows that overlap.
1.973 + The two windows are placed in exactly the same location, so the result of splitting the drawing across them should be "identical".
1.974 + Note that when the anim and the draw are on different screens the lines are seen merged over the anim.
1.975 +**/
1.976 +void CTCrpAnim::TestOverlappingWindowsL()
1.977 + {
1.978 + if (!iOverWin)
1.979 + {
1.980 + INFO_PRINTF1(_L("- Test skipped - transparency not supported"));
1.981 + return;
1.982 + }
1.983 +
1.984 + // setup necessary params
1.985 + // Note we place the overlapping transparent window (iOverWin) directly on top of the test window (iTestWin)
1.986 + iOverWin->BaseWin()->SetPosition(iTestWin->BaseWin()->Position());
1.987 +
1.988 + enum
1.989 + {
1.990 + EAllBackground=0,
1.991 + EForegroundDraw=1,
1.992 + EForegroundAnim=2,
1.993 + EAllForeGround=3,
1.994 + ECountModes,
1.995 + EFirstMode=EAllBackground,
1.996 + };
1.997 +
1.998 + // test the various permutations of overlapping vs animated windows
1.999 + for (TInt mode = EFirstMode ; mode < ECountModes ; mode++)
1.1000 + {
1.1001 + INFO_PRINTF2(_L("TestOverlappingWindowsL [%d]"), mode);
1.1002 + TestSpriteLoopL((mode&EForegroundAnim)!=0,(mode&EForegroundDraw)!=0);
1.1003 + }
1.1004 + }
1.1005 +
1.1006 +/**
1.1007 + This method demonstrates clipping of an animation running behind a transparent window.
1.1008 + No main window redraw takes place here.
1.1009 +**/
1.1010 +void CTCrpAnim::DemoClippingWindowsL()
1.1011 + {
1.1012 + if (!iOverWin)
1.1013 + {
1.1014 + INFO_PRINTF1(_L("- Test skipped - transparency not supported"));
1.1015 + return;
1.1016 + }
1.1017 +
1.1018 + // setup test case params. Note we calculate three different positions for the overlapping window
1.1019 + RWindow* win = iTestWin->Window();
1.1020 +
1.1021 + TPoint screenPos= win->Position();
1.1022 + TSize screenSize = win->Size();
1.1023 + TRect subposition1(screenSize);
1.1024 + CalcCentredAnimPosition(subposition1, screenSize);
1.1025 +
1.1026 + TPoint testPositions[]=
1.1027 + {
1.1028 + //first test: window clips corner of anim
1.1029 + TPoint(screenPos.iX+screenSize.iWidth/2-10,screenPos.iY+screenSize.iHeight/2-10),
1.1030 + //test: window clips all of anim
1.1031 + TPoint(screenPos.iX+screenSize.iWidth/3,screenPos.iY+screenSize.iHeight/3),
1.1032 + //test: window clips none of anim
1.1033 + TPoint(screenPos.iX+screenSize.iWidth*2/3,screenPos.iY+screenSize.iHeight*2/3),
1.1034 + };
1.1035 +
1.1036 + // calculate roughly number of frames we expect to have drawn
1.1037 + TInt loopWaitTime = KShortDelayLoop; // time given to allow animation to progress (arbitrary number)
1.1038 + float expectedFrameCount = 1;
1.1039 + if (loopWaitTime > KAnimationFrameDelayTime)
1.1040 + {
1.1041 + expectedFrameCount = loopWaitTime/KAnimationFrameDelayTime;
1.1042 + }
1.1043 +
1.1044 + for (TInt ii = 0; ii < ((sizeof testPositions)/(sizeof testPositions[0])) ; ii++)
1.1045 + {
1.1046 + // initialise test windows to known state with no active animations
1.1047 + ResetFrameCounters();
1.1048 + iTestWin->RemoveAnimation(KUidTestAnimation2);
1.1049 + iTestWin->SetBlankIt(EFalse);
1.1050 + iOverWin->SetBlankIt(ETrue);
1.1051 + iOverWin->RemoveAnimation(KUidTestAnimation2);
1.1052 +
1.1053 + // position animation windows
1.1054 + iTestWin->SetAnimation(KUidTestAnimation2)->Play(ETrue);
1.1055 + iTestWin->SetPosAnimation(KUidTestAnimation2, subposition1);
1.1056 + iOverWin->BaseWin()->SetPosition(testPositions[ii]); // positions the transparent overlapping window
1.1057 +
1.1058 + // redraw both test windows
1.1059 + iTestWin->InvalidateAndRedraw(ETrue,EFalse,ETrue);
1.1060 + iOverWin->InvalidateAndRedraw(ETrue,EFalse,ETrue);
1.1061 +
1.1062 + // run the animation for an arbitrary period
1.1063 + for (TInt loopit = 0 ; loopit < 20 ; loopit++)
1.1064 + {
1.1065 + iWaiter->Wait(loopWaitTime);
1.1066 + CheckAnimProgressedL(iTestWin,static_cast<TInt>(expectedFrameCount)); // log the frame result
1.1067 + }
1.1068 +
1.1069 + // calculate & log frame results. Test an acceptable number of frames were successfully animated
1.1070 + TInt total = LogResults();
1.1071 + TInt qA = 100*iFrameStatus.iFrameOK/total;
1.1072 + TEST(qA > KMinGoodFrameThreshold);
1.1073 + }
1.1074 + }
1.1075 +
1.1076 +/** In this version, the background window is updated in patches.
1.1077 + If the animation intersects the transparent window then the whole transparent window is redrawn.
1.1078 +**/
1.1079 +void CTCrpAnim::TestClippingWindowsL()
1.1080 + {
1.1081 + if (!iOverWin)
1.1082 + {
1.1083 + INFO_PRINTF1(_L("- Test skipped - transparency not supported"));
1.1084 + return;
1.1085 + }
1.1086 + // setup test case params. Note we calculate three different positions for the overlapping window
1.1087 + RWindow* win = iTestWin->Window();
1.1088 + TPoint screenPos= win->Position();
1.1089 + TSize screenSize = win->Size();
1.1090 +
1.1091 + TPoint testPositions[]=
1.1092 + {
1.1093 + //first test: window clips corner of anim
1.1094 + TPoint(screenPos.iX+screenSize.iWidth/2-10,screenPos.iY+screenSize.iHeight/2-10),
1.1095 + //test: window clips all of anim
1.1096 + TPoint(screenPos.iX+screenSize.iWidth/3,screenPos.iY+screenSize.iHeight/3),
1.1097 + //test: window clips none of anim
1.1098 + TPoint(screenPos.iX+screenSize.iWidth*2/3,screenPos.iY+screenSize.iHeight*2/3),
1.1099 + };
1.1100 +
1.1101 + for (TInt loopIt = 0; loopIt < ((sizeof testPositions)/(sizeof testPositions[0])) ; loopIt++)
1.1102 + {
1.1103 + iOverWin->BaseWin()->SetPosition(testPositions[loopIt]); // position the overlapping window
1.1104 + TestSpriteLoopL(EFalse,EFalse);
1.1105 + }
1.1106 + }
1.1107 +
1.1108 +/** This just demonstrates that an animation plays - for about 1 second.
1.1109 +**/
1.1110 +void CTCrpAnim::BasicCRPDemo()
1.1111 + {
1.1112 + // draw the animation in two positions
1.1113 + TSize subsize1 = iTestWin->BaseWin()->Size();
1.1114 + TRect subposition1(subsize1);
1.1115 + CalcCentredAnimPosition(subposition1, subsize1);
1.1116 +
1.1117 + if (iOverWin)
1.1118 + {
1.1119 + iOverWin->BaseWin()->SetPosition(KPointOffsite); //way away!
1.1120 + iOverWin->InvalidateAndRedraw(EFalse,EFalse,ETrue);
1.1121 + }
1.1122 +
1.1123 + CCrpAnim *animWin= iTestWin;
1.1124 + animWin->SetAnimation(KUidTestAnimation2)->Play(ETrue);
1.1125 + animWin->SetPosAnimation(KUidTestAnimation2, subposition1);
1.1126 + iTestWin->InvalidateAndRedraw(ETrue,EFalse,ETrue);
1.1127 + iBaseWin->InvalidateAndRedraw(ETrue,EFalse,ETrue);
1.1128 +
1.1129 + // allow the animation to play for ~1 second. Purpose is to demonstrate animation to an observer
1.1130 + iWaiter->Wait(KShortDelayLoop);
1.1131 +
1.1132 + ResetFrameCounters();
1.1133 + iWaiter->Cancel();
1.1134 + iTestWin->RemoveAnimation(KUidTestAnimation2);
1.1135 + }
1.1136 +
1.1137 +/**
1.1138 +@SYMTestCaseID GRAPHICS-WSERV-CRP01-0001
1.1139 +
1.1140 +@SYMDEF DEF100356
1.1141 +
1.1142 +@SYMTestCaseDesc CRP animation test for redraw storing interrupting main draw
1.1143 +
1.1144 +@SYMTestPriority High
1.1145 +
1.1146 +@SYMTestStatus Implemented
1.1147 +
1.1148 +@SYMTestActions Creates a CRP animation and runs it on the server scheduler
1.1149 + while also running redraws of the window.
1.1150 +
1.1151 + With Redraw storing this has been known to cause problems
1.1152 + sharing and resetting the window iDisplayRegion.
1.1153 + This is evidenced by white areas.
1.1154 +
1.1155 +
1.1156 +@SYMTestExpectedResults
1.1157 + The LHS window shows what the animation should look like just animating,
1.1158 + while the RHS window demonstrates the simultanious animation and redraw.
1.1159 + No White patches should be in evidence, and no missing fragments of animation.
1.1160 + The TEST should detect white patches.
1.1161 +*/
1.1162 +void CTCrpAnim::TestSpriteInterruptsForegroundL()
1.1163 + {
1.1164 + // setup test params
1.1165 + TSize subsize1(iTestWin->BaseWin()->Size());
1.1166 + TRect subposition1(subsize1);
1.1167 + CalcCentredAnimPosition(subposition1, subsize1);
1.1168 + if (iOverWin)
1.1169 + {
1.1170 + iOverWin->BaseWin()->SetPosition(KPointOffsite); // ensure overlapping transparent window DOESN'T overlap the test window
1.1171 + }
1.1172 +
1.1173 + // execute test loop
1.1174 + TestSpriteLoopL(EFalse,EFalse);
1.1175 + }
1.1176 +
1.1177 +void CTCrpAnim::RunTestCaseL(TInt /*aCurTestCase*/)
1.1178 + {
1.1179 + _LIT(KTest1,"1: Basic CRP demo");
1.1180 + _LIT(KTest2,"2: sprite anim interrupts foreground");
1.1181 + _LIT(KTest3,"3: translucent windows");
1.1182 + _LIT(KTest4,"4: CRP clipping windows");
1.1183 + _LIT(KTest5,"5: CRP & redraw clipping windows");
1.1184 + _LIT(KTest6,"6: CRP Invalidation");
1.1185 +
1.1186 + ((CTCrpAnimStep*)iStep)->SetTestStepID(KUnknownSYMTestCaseIDName);
1.1187 + switch(++iTest->iState)
1.1188 + {
1.1189 + case 1:
1.1190 +/**
1.1191 +@SYMTestCaseID GRAPHICS-WSERV-CRP01-0002
1.1192 +*/
1.1193 + ((CTCrpAnimStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-CRP01-0002"));
1.1194 + iTest->LogSubTest(KTest1);
1.1195 + BasicCRPDemo();
1.1196 + break;
1.1197 + case 2:
1.1198 + ((CTCrpAnimStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-CRP01-0001"));
1.1199 + iTest->LogSubTest(KTest2);
1.1200 + TestSpriteInterruptsForegroundL();
1.1201 + break;
1.1202 + case 3:
1.1203 +/**
1.1204 +@SYMTestCaseID GRAPHICS-WSERV-CRP01-0003
1.1205 +*/
1.1206 + ((CTCrpAnimStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-CRP01-0003"));
1.1207 + iTest->LogSubTest(KTest3);
1.1208 + TestOverlappingWindowsL();
1.1209 + break;
1.1210 + case 4:
1.1211 +/**
1.1212 +@SYMTestCaseID GRAPHICS-WSERV-CRP01-0004
1.1213 +*/
1.1214 + ((CTCrpAnimStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-CRP01-0004"));
1.1215 + iTest->LogSubTest(KTest4);
1.1216 + DemoClippingWindowsL();
1.1217 + break;
1.1218 + case 5:
1.1219 +/**
1.1220 +@SYMTestCaseID GRAPHICS-WSERV-CRP01-0005
1.1221 +*/
1.1222 + ((CTCrpAnimStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-CRP01-0005"));
1.1223 + iTest->LogSubTest(KTest5);
1.1224 + TestClippingWindowsL();
1.1225 + break;
1.1226 + case 6:
1.1227 +/**
1.1228 +@SYMTestCaseID GRAPHICS-WSERV-CRP01-0006
1.1229 +*/
1.1230 + ((CTCrpAnimStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-CRP01-0006"));
1.1231 + iTest->LogSubTest(KTest6);
1.1232 + //this testcase is removed, because invalidation is removed from CWsGraphicDrawer destructor (due to flickering)
1.1233 + break;
1.1234 + default:
1.1235 + ((CTCrpAnimStep*)iStep)->SetTestStepID(KNotATestSYMTestCaseIDName);
1.1236 + ((CTCrpAnimStep*)iStep)->CloseTMSGraphicsStep();
1.1237 + TestComplete();
1.1238 + }
1.1239 + ((CTCrpAnimStep*)iStep)->RecordTestResultL();
1.1240 + }
1.1241 +
1.1242 +//
1.1243 +namespace //anonymous namespace
1.1244 + {
1.1245 +//
1.1246 + CAnimRedrawWindow::CAnimRedrawWindow(CCrpAnim *aAnimWindow, TBool aIsBase) : CTWin(),
1.1247 + iAnimWindow(aAnimWindow),
1.1248 + iIsBase(aIsBase)
1.1249 + {
1.1250 + }
1.1251 +
1.1252 + CAnimRedrawWindow::~CAnimRedrawWindow()
1.1253 + {
1.1254 + }
1.1255 +
1.1256 + void CAnimRedrawWindow::Draw()
1.1257 + {
1.1258 + CCrpAnim::Draw(Gc(),Size(),iIsBase,iAnimWindow->iRect,iAnimWindow->iBlankIt,iAnimWindow->iRepeatDrawMax,iAnimWindow->iAlphaValue);
1.1259 + if (iAnimWindow->iAnimUid!=TUid::Null())
1.1260 + {
1.1261 + TheClient->Flush();
1.1262 + Gc()->DrawWsGraphic(iAnimWindow->iAnimUid,iAnimWindow->iAnimPos,iAnimWindow->iAnimData.Pckg());
1.1263 + TheClient->Flush();
1.1264 + }
1.1265 + }
1.1266 +
1.1267 + //
1.1268 +
1.1269 + CCrpAnim::CCrpAnim(TBool aIsBase, TWinType aWinType)
1.1270 + : iWinType(aWinType),
1.1271 + iIsBase(aIsBase),
1.1272 + iBlankIt(EFalse),
1.1273 + iRepeatDrawMax(1),
1.1274 + iAnimUid(TUid::Null()),
1.1275 + iAlphaValue(ENoTransparency)
1.1276 + {
1.1277 + }
1.1278 +
1.1279 + CCrpAnim::~CCrpAnim()
1.1280 + {
1.1281 + delete iCtWin;
1.1282 + }
1.1283 +
1.1284 + void CCrpAnim::ConstructL(const TPoint &aPos, const TSize &aSize, TInt aAlphaValue)
1.1285 + {
1.1286 + TDisplayMode reqMode = EColor16MA; //for transparency we need 16ma or 16map mode
1.1287 + TDisplayMode *pReqMode=&reqMode;
1.1288 + switch(iWinType)
1.1289 + {
1.1290 + case ERedraw:
1.1291 + iCtWin = new(ELeave) CAnimRedrawWindow(this, iIsBase);
1.1292 + break;
1.1293 + case EBlank:
1.1294 + iCtWin = new(ELeave) CTBlankWindow();
1.1295 + break;
1.1296 + case EBackedUp:
1.1297 + iCtWin = new(ELeave) CTBackedUpWin(EColor64K);
1.1298 + pReqMode = NULL;
1.1299 + break;
1.1300 + }
1.1301 + iCtWin->SetUpL(aPos, aSize, TheClient->iGroup, *TheClient->iGc, pReqMode, ETrue);
1.1302 + if (aAlphaValue != ENoTransparency)
1.1303 + {
1.1304 + User::LeaveIfError(Window()->SetTransparencyAlphaChannel());
1.1305 + //the window itself should be completely transparent, the draw commands will use the alpha value
1.1306 + Window()->SetBackgroundColor(TRgb(0, 0, 0, 0));
1.1307 + iAlphaValue = aAlphaValue;
1.1308 + }
1.1309 + }
1.1310 +
1.1311 + void CCrpAnim::SetEllipseDrawMode(CGraphicsContext::TDrawMode aEllipseDrawMode)
1.1312 + {
1.1313 + iEllipseDrawMode = aEllipseDrawMode;
1.1314 + }
1.1315 +
1.1316 + void CCrpAnim::DrawEllipse(CBitmapContext *aGc, const TRect &aRect, TInt aAlphaValue)
1.1317 + {
1.1318 + if(aAlphaValue != ENoTransparency)
1.1319 + {
1.1320 + aGc->SetBrushColor(TRgb(85,85,85, aAlphaValue));
1.1321 + aGc->SetPenColor(TRgb(170,170,170, aAlphaValue));
1.1322 + }
1.1323 + else
1.1324 + {
1.1325 + aGc->SetBrushColor(TRgb(85,85,85));
1.1326 + aGc->SetPenColor(TRgb(170,170,170));
1.1327 + }
1.1328 + aGc->SetDrawMode(iEllipseDrawMode);
1.1329 + aGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
1.1330 + aGc->DrawEllipse(aRect);
1.1331 + }
1.1332 +
1.1333 + void CCrpAnim::Draw(CBitmapContext *aGc, const TSize &aSize, TBool aIsBase, const TRect &aRect, TBool aBlankIt,TInt aRepeat, TInt aAlphaValue)
1.1334 + {
1.1335 + static TInt sGrey=0;
1.1336 + sGrey+=3;
1.1337 + if (sGrey>0x40)
1.1338 + sGrey-=0x40;
1.1339 + sGrey=sGrey^0x20;
1.1340 + if(aAlphaValue != ENoTransparency)
1.1341 + {
1.1342 + aGc->SetBrushColor(TRgb(sGrey, sGrey, sGrey, aAlphaValue));
1.1343 + aGc->SetPenColor(TRgb(KRgbGreen.Value(), aAlphaValue));
1.1344 + }
1.1345 + else
1.1346 + {
1.1347 + aGc->SetBrushColor(TRgb::Gray256(sGrey));
1.1348 + aGc->SetPenColor(KRgbGreen);
1.1349 + }
1.1350 + aGc->Clear();
1.1351 + TInt xPos=aSize.iHeight,yPos=aSize.iWidth;
1.1352 +
1.1353 + // The test windows are created relative to screen size. The
1.1354 + // number of green lines generated needs to be tied into the
1.1355 + // window size to prevent green becoming the dominant colour
1.1356 + // when blended with the second animation, which would
1.1357 + // prevent the PredominantColour() algorithm from discovering
1.1358 + // the red line.
1.1359 + TInt yStep = aSize.iHeight/14;
1.1360 + TInt xStep = aSize.iWidth/6;
1.1361 +
1.1362 + //This paint is intentionally complex and slow so that the animation timer is likely to interrupt it.
1.1363 + if (!aBlankIt)
1.1364 + for (TInt nn = 0 ; nn < aRepeat ; nn++)
1.1365 + for(yPos=0 ; yPos < aSize.iHeight ; yPos += yStep)
1.1366 + for(xPos=0 ; xPos < aSize.iWidth ; xPos += xStep)
1.1367 + aGc->DrawLine(aRect.Center(),TPoint(xPos,yPos));
1.1368 + if (aIsBase)
1.1369 + DrawEllipse(aGc, aRect, aAlphaValue);
1.1370 + }
1.1371 +
1.1372 + //This simple API may need replacing by a list and search if multiple anims are played together
1.1373 + TWsGraphicAnimation* CCrpAnim::SetAnimation(TUid aUid)
1.1374 + { //currently only have 1 animation - it gets replaced. It could get refiused
1.1375 + iAnimUid=aUid;
1.1376 + return &iAnimData;
1.1377 + }
1.1378 +
1.1379 + TWsGraphicAnimation* CCrpAnim::GetAnimation(TUid aUid)
1.1380 + { //currently only have 1 animation
1.1381 + if (iAnimUid==aUid)
1.1382 + return &iAnimData;
1.1383 + else
1.1384 + return NULL;
1.1385 + }
1.1386 +
1.1387 + void CCrpAnim::SetPosAnimation(const TUid& aUid, const TRect& aRect)
1.1388 + { //currently only have 1 animation
1.1389 + if (iAnimUid==aUid)
1.1390 + iAnimPos = aRect;
1.1391 + }
1.1392 +
1.1393 + TRect* CCrpAnim::GetPosAnimation(const TUid& aUid)
1.1394 + { //currently only have 1 animation
1.1395 + if (iAnimUid==aUid)
1.1396 + return &iAnimPos;
1.1397 + else
1.1398 + return NULL;
1.1399 + }
1.1400 +
1.1401 + TBool CCrpAnim::RemoveAnimation(TUid)
1.1402 + {
1.1403 + iAnimUid=TUid::Null();
1.1404 + iAnimData.Stop(EFalse);
1.1405 + return ETrue;
1.1406 + }
1.1407 +
1.1408 + void CCrpAnim::DoDraw()
1.1409 + {
1.1410 + DoDraw(iBlankIt);
1.1411 + }
1.1412 +
1.1413 + inline void CCrpAnim::DoDraw(TBool aBlankIt)
1.1414 + {
1.1415 + __ASSERT_ALWAYS(iWinType!=EBlank,AutoPanic(EAutoPanicWindowType));
1.1416 + iCtWin->Gc()->Activate(*Window());
1.1417 + Draw(iCtWin->Gc(),Size(),iIsBase,iRect,aBlankIt,iRepeatDrawMax,iAlphaValue);
1.1418 + if (iAnimUid!=TUid::Null())
1.1419 + iCtWin->Gc()->DrawWsGraphic(iAnimUid,iAnimPos,iAnimData.Pckg());
1.1420 + iCtWin->Gc()->Deactivate();
1.1421 + }
1.1422 +
1.1423 + void CCrpAnim::DoDrawEllipse()
1.1424 + {
1.1425 + __ASSERT_ALWAYS(iWinType!=EBlank,AutoPanic(EAutoPanicWindowType));
1.1426 + iCtWin->Gc()->Activate(*Window());
1.1427 + DrawEllipse(iCtWin->Gc(),iRect,iAlphaValue);
1.1428 + iCtWin->Gc()->Deactivate();
1.1429 + }
1.1430 +
1.1431 + void CCrpAnim::InvalidateAndRedraw(TBool /*aUseBlankItMember*/,TBool /*aBlankIt*/,TBool aUseRWindowInvalidate,TRect* aRect)
1.1432 + {
1.1433 + RWindow& win = *Window();
1.1434 + if (aRect)
1.1435 + {
1.1436 + if (aUseRWindowInvalidate)
1.1437 + win.Invalidate(*aRect);
1.1438 + else
1.1439 + Invalidate(*aRect);
1.1440 + }
1.1441 + else
1.1442 + {
1.1443 + if (aUseRWindowInvalidate)
1.1444 + win.Invalidate();
1.1445 + else
1.1446 + Invalidate();
1.1447 + }
1.1448 + if (aRect)
1.1449 + win.BeginRedraw(*aRect);
1.1450 + else
1.1451 + win.BeginRedraw();
1.1452 + DoDraw();
1.1453 + win.EndRedraw();
1.1454 + TheClient->Flush();
1.1455 + }
1.1456 +
1.1457 + void CCrpAnim::Invalidate(const TRect &aRect)
1.1458 + {
1.1459 + TRect rect(aRect);
1.1460 + rect.Move(iCtWin->Position());
1.1461 + CTUser::Splat(TheClient,rect,TRgb::Gray256(0));
1.1462 + }
1.1463 +
1.1464 +//
1.1465 + } //end anonymous namespace
1.1466 +//
1.1467 +__WS_CONSTRUCT_STEP__(CrpAnim)