diff -r 000000000000 -r bde4ae8d615e os/graphics/graphicsdeviceinterface/bitgdi/tbit/TAlphaBlend.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/graphics/graphicsdeviceinterface/bitgdi/tbit/TAlphaBlend.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,1038 @@ +// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include +#include +#include "TAlphaBlend.h" + + +const TInt KWidth = 10;//Used in alpha blending tests +const TInt KHeight = 3;//Used in alpha blending tests +const TInt KMaximumAttempts = 2; // Allow retries on some tests, due to spurious InfoPrints +TBool iExtraLogging1=EFalse; //Used to trigger logging at times the test fails +TBool iExtraLogging2=EFalse; //Used to trigger logging at times the test fails + +CTAlphaBlending::CTAlphaBlending(CTestStep* aStep): + CTGraphicsBase(aStep), + iDevice(NULL), + iGc(NULL) + { + } + +CTAlphaBlending::~CTAlphaBlending() + { + DeleteGraphicsContext(); + DeleteScreenDevice(); + } + +void CTAlphaBlending::RunTestCaseL(TInt aCurTestCase) + { + ((CTAlphaBlendingStep*)iStep)->SetTestStepID(KUnknownSYMTestCaseIDName); + switch(aCurTestCase) + { + case 1: + ((CTAlphaBlendingStep*)iStep)->SetTestStepID(_L("GRAPHICS-BITGDI-0024")); + INFO_PRINTF1(_L("Alpha blending")); + TestAlphaBlendingL(); + break; + case 2: +/** +@SYMTestCaseID GRAPHICS-BITGDI-0114 +*/ + ((CTAlphaBlendingStep*)iStep)->SetTestStepID(_L("GRAPHICS-BITGDI-0114")); + INFO_PRINTF1(_L("Alpha blending 2")); + TestAlphaBlending2L(); + break; + case 3: + ((CTAlphaBlendingStep*)iStep)->SetTestStepID(_L("GRAPHICS-BITGDI-0085")); + INFO_PRINTF1(_L("Alpha blending Correctness test 16MU 16MA")); + TestAlphaBlendCorrect(EColor16MU, EColor16MU); + break; + case 4: + ((CTAlphaBlendingStep*)iStep)->SetTestStepID(_L("GRAPHICS-BITGDI-0097")); + INFO_PRINTF1(_L("Alpha plot test")); + TestAlphaBlendingPlotL(); + break; + case 5: +/** +@SYMTestCaseID GRAPHICS-BITGDI-0115 +*/ + ((CTAlphaBlendingStep*)iStep)->SetTestStepID(_L("GRAPHICS-BITGDI-0115")); + INFO_PRINTF1(_L("Draw bitmap blending")); + DoDrawBitmapTestsL(); + break; + case 6: + //DEF118268 + ((CTAlphaBlendingStep*)iStep)->SetTestStepID(_L("GRAPHICS-BITGDI-0085")); + INFO_PRINTF1(_L("Alpha blending Correctness test 16M 16MA")); + TestAlphaBlendCorrect(EColor16M, EColor16MA); + break; + case 7: + ((CTAlphaBlendingStep*)iStep)->SetTestStepID(KNotATestSYMTestCaseIDName); + ((CTAlphaBlendingStep*)iStep)->CloseTMSGraphicsStep(); + TestComplete(); + break; + } + ((CTAlphaBlendingStep*)iStep)->RecordTestResultL(); + } + +TInt CTAlphaBlending::CreateScreenDevice(TDisplayMode aDisplayMode, CFbsBitGc::TGraphicsOrientation aOrientation) + { + DeleteGraphicsContext(); + DeleteScreenDevice(); + TRAPD(err, iDevice = CFbsScreenDevice::NewL(_L("scdv"), aDisplayMode)); + if(err == KErrNotSupported) + { + return err; + } + TEST2(err, KErrNone); + err = iDevice->CreateContext((CGraphicsContext*&)iGc); + TEST2(err, KErrNone); + if (!iGc->SetOrientation(aOrientation)) + { + return(KErrNotSupported); + } + iGc->SetUserDisplayMode(aDisplayMode); + iDevice->ChangeScreenDevice(NULL); + iDevice->SetAutoUpdate(EFalse); + return err; + } + +void CTAlphaBlending::DeleteScreenDevice() + { + delete iDevice; + iDevice = NULL; + } + +void CTAlphaBlending::DeleteGraphicsContext() + { + delete iGc; + iGc = NULL; + } + +// returns the pixel colour from the provided bitmap in aarrggbb format +// if pixel is outside the bitmaps limits return top left pixel +TUint32 CTAlphaBlending::GetRawPixel(CFbsBitmap* aBitmap, TPoint aPos) + { + TBitmapUtil bmpUtil(aBitmap); + TUint32 value = 0; + ASSERT(aPos.iX>=0 && aPos.iY>=0); + ASSERT(aPos.iXSizeInPixels().iWidth && aPos.iYSizeInPixels().iHeight); + bmpUtil.Begin(aPos); + value = bmpUtil.GetPixel(); + bmpUtil.End(); + return value; + } + +/** +@SYMTestCaseID GRAPHICS-BITGDI-0097 + +@SYMDEF DEF113229 + +@SYMTestCaseDesc CDrawThirtyTwoBppBitmapCommon::WriteRgb did not change the dest alpha value to 255 when + the dest alpha was >0 and <255 and the a soure pen had an alpha of 255 + +@SYMTestPriority Normal + +@SYMTestStatus Implemented + +@SYMTestActions Creates a bitmap, clears it to black (destination) 50% opaque then plots a series of points + with a 100% opaque pen on it. Tests the resultant alpha value. + +@SYMTestExpectedResults Final alpha value should be 255 +**/ +void CTAlphaBlending::TestAlphaBlendingPlotL() + { + const TSize KRectSize(100,100); + const TRect KTargetRect(TPoint(0,0), KRectSize); + + // create the target bitmap + CFbsBitmap* destBmp = new (ELeave) CFbsBitmap; + CleanupStack::PushL(destBmp); + User::LeaveIfError(destBmp->Create(KRectSize, EColor16MA)); + destBmp->SetSizeInTwips(KRectSize); + + // create bitmap device and graphics context + CFbsBitmapDevice* destBmpDevice = CFbsBitmapDevice::NewL(destBmp); + CleanupStack::PushL(destBmpDevice); + CFbsBitGc* destGc = NULL; + User::LeaveIfError(destBmpDevice->CreateContext(destGc)); + CleanupStack::PushL(destGc); + destGc->SetPenStyle(CGraphicsContext::ENullPen); + destGc->SetBrushStyle(CGraphicsContext::ESolidBrush); + + TDisplayMode screenMode = EColor16MA; + TInt err = CreateScreenDevice(screenMode); + if (err != KErrNone) + { + screenMode = EColor64K; + err = CreateScreenDevice(screenMode); + } + + if(err==KErrNone) + { + const TInt KSqrMin=45; + const TInt KSqrMax=55; + + iGc->SetUserDisplayMode(screenMode); + destGc->SetBrushColor(TRgb(0,0,0,127)); + destGc->SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha); + destGc->Clear(KTargetRect); + + // copy over to screen dc for anyone watching + iGc->BitBlt(TPoint(0,0), destBmp, KTargetRect); + iDevice->Update(); + + // set the pen colour to white and plot some points + destGc->SetDrawMode(CGraphicsContext::EDrawModePEN); + destGc->SetPenStyle(CGraphicsContext::ESolidPen); + destGc->SetPenColor(TRgb(0,70,130,255)); + for( TInt y=KSqrMin;y<=KSqrMax;y++) + { + for( TInt x=KSqrMin;x<=KSqrMax;x++) + { + destGc->Plot(TPoint(x,y)); + } + } + + // copy over to screen dc for anyone watching + iGc->BitBlt(TPoint(0,0), destBmp, KTargetRect); + iDevice->Update(); + + TUint32 actualValue=0; + // check the resulting values alpha values are 0xFF in the square we drew + for( TInt y=KSqrMin;y<=KSqrMax;y++) + { + for( TInt x=KSqrMin;x<=KSqrMax;x++) + { + actualValue = GetRawPixel(destBmp, TPoint(x,y)); + if( (actualValue&0xFF000000) != 0xFF000000 ) + { + TEST(EFalse); + INFO_PRINTF2(_L("TestAlphaBlendingPlotL() ***FAILED*** - expected alpha value 0xFF got %d "),((actualValue&0xFF000000)>>24)); + } + } + } + } + CleanupStack::PopAndDestroy(3); //destGc,destBmpDevice,destBmp + } + +/** + @SYMTestCaseID GRAPHICS-BITGDI-0024 + + @SYMDEF + + @SYMTestCaseDesc + + System, GT0173 System Libraries, BITGDI support required for semi-transparent windows + DEF039083 - Using BitBltMasked to do alpha-blending only works if your brush style is "null" + DEF039409 - Wrong part of Alpha Bitmap is used when there is a clipping region + DEF039669 - The UserDisplayMode is not honoured during the AlphaBlendBitmap function. + REQ3413 Second overload of CFbsBitGc's AlphaBlendBitmaps - "Supply a second overload of + CFbsBitGc's AlphaBlendBitmaps function, but with one of the source bitmaps being passed + as a CFbsBitGc object, so that the screen can be used as a source." + + @SYMTestPriority High + + @SYMTestStatus Implemented + + @SYMTestActions + + Tests alpha blending - for all display modes, some brush styles, user display modes, + different positions on the screen. + + Shadow/fade mode is no more tested, because the existing BitBltMasked() and the new + AlphaBlendBitmaps() methods treat it a different way - see MAlphaBlend interface in + ScreenDriver component. + + @SYMTestExpectedResults Test should perform graphics operations succesfully. +*/ + +void CTAlphaBlending::TestAlphaBlendingL() + { + TPoint originPt(0, 0); + TPoint destPt(0, 0); + TRect scrRc1(0, 0, KWidth, KHeight); + TPoint srcPt2(0, 0); + TPoint alphaPt(0, 0); + // + //If we compare CFbsBitGc::BitBltMasked() aguments with CFbsBitGc::AlphaBlending() arguments, + //we will see that AlphaBlending() has more arguments than BitBltMasked() - + //srcPt2, alphaPt. To make it possible - the comparison between these two methods, + //we have to change aAlphaPt and aSrcPt2 values accordingly with the changes of scrRc1 value. + // + //test 1 - the origin is moved + originPt = TPoint(97, 33); + DoAlphaBlendingTestsL(originPt, destPt, scrRc1, srcPt2, alphaPt); +#if !defined(__X86GCC__) //These test take too long to run in X86GCC + //test 2 - the origin is (0, 0) + originPt = TPoint(0, 0); + DoAlphaBlendingTestsL(originPt, destPt, scrRc1, srcPt2, alphaPt); + //test 3 - scrRect1 is not (0, 0, KWidth, KHeight) + scrRc1 = TRect(3, 1, KWidth, KHeight); + alphaPt = TPoint(3, 1); + DoAlphaBlendingTestsL(originPt, destPt, scrRc1, srcPt2, alphaPt); + //test 4 - restore scrRc1 and alphaPt, move the destination point + scrRc1 = TRect(0, 0, KWidth, KHeight); + alphaPt = TPoint(0, 0); + destPt = TPoint(13, 17); + iExtraLogging1=ETrue; + DoAlphaBlendingTestsL(originPt, destPt, scrRc1, srcPt2, alphaPt); + iExtraLogging1=EFalse; +#endif //__X86GCC__ + } + +void CTAlphaBlending::DoDrawBitmapTestsL() + { + TDisplayMode modes[] = {EColor16MA, EColor16MAP, EColor16MU, EColor16M, EColor256, EColor4K, EColor64K, + EGray256, EGray16, EGray4, EGray2, EColor16}; + const TInt KNumTestDisplayModes=sizeof(modes)/sizeof(modes[0]); + for(TInt modeIndex=0;modeIndexReset(); + TBool alphaSupported=(aTestDisplayMode==EColor16MA || aTestDisplayMode==EColor16MAP); + TSize screenSize=iDevice->SizeInPixels(); +// + const TInt KNumTestSrcSizes=4; + const TSize testSrcSizes[KNumTestSrcSizes]={TSize(2,2),TSize(20,10),TSize(200,5),TSize(55,555)}; + for(TInt srcSizeIndex=0;srcSizeIndexCreate(srcSize,aTestDisplayMode)); + CFbsBitmapDevice* srcDevice = CFbsBitmapDevice::NewL(srcBmp); + CleanupStack::PushL(srcDevice); + CFbsBitGc* srcGc=NULL; + User::LeaveIfError(srcDevice->CreateContext(srcGc)); + CleanupStack::PushL(srcGc); +// + CFbsBitmap* srcAlpha=new(ELeave) CFbsBitmap; + CleanupStack::PushL(srcAlpha); + User::LeaveIfError(srcAlpha->Create(srcSize,aTestDisplayMode)); + CFbsBitmapDevice* srcAlphaDevice = CFbsBitmapDevice::NewL(srcAlpha); + CleanupStack::PushL(srcAlphaDevice); + CFbsBitGc* srcAlphaGc=NULL; + User::LeaveIfError(srcAlphaDevice->CreateContext(srcAlphaGc)); + CleanupStack::PushL(srcAlphaGc); + srcAlphaGc->SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha); +// + CFbsBitmap* srcMask=new(ELeave) CFbsBitmap; + CleanupStack::PushL(srcMask); + User::LeaveIfError(srcMask->Create(srcSize,EGray256)); + CFbsBitmapDevice* srcMaskDevice = CFbsBitmapDevice::NewL(srcMask); + CleanupStack::PushL(srcMaskDevice); + CFbsBitGc* srcMaskGc=NULL; + User::LeaveIfError(srcMaskDevice->CreateContext(srcMaskGc)); + CleanupStack::PushL(srcMaskGc); +// + TInt maxX=srcSize.iWidth-1; + TInt maxY=srcSize.iHeight-1; + for(TInt yLoop=0;yLoopSetPenColor(pen); + srcGc->Plot(plotPos); + TInt alpha=(xLoop+yLoop)*255/(maxX+maxY); + pen.SetAlpha(alpha); + srcAlphaGc->SetBrushColor(pen); + srcAlphaGc->Clear(TRect(plotPos,TSize(1,1))); + srcMaskGc->SetPenColor(TRgb::Gray256(alpha)); + srcMaskGc->Plot(plotPos); + } + } + const TInt KNumTestTargSizes=5; + const TSize testTargSizes[KNumTestTargSizes]={TSize(0,0), TSize(20,1),TSize(30,20),TSize(200,31),TSize(55,5)}; + for(TInt targSizeIndex=0;targSizeIndexscreenSize.iWidth) + targSize.iWidth=screenSize.iWidth; + TInt maxHeight=screenSize.iHeight/3; + if (targSize.iHeight>maxHeight) + targSize.iHeight=maxHeight; + } +// + CFbsBitmap* targBmp=new(ELeave) CFbsBitmap; + CleanupStack::PushL(targBmp); + User::LeaveIfError(targBmp->Create(targSize,aTestDisplayMode)); + CFbsBitmapDevice* targBmpDevice = CFbsBitmapDevice::NewL(targBmp); + CleanupStack::PushL(targBmpDevice); + CFbsBitGc* targGc=NULL; + User::LeaveIfError(targBmpDevice->CreateContext(targGc)); + CleanupStack::PushL(targGc); +// + CFbsBitmap* targMask=new(ELeave) CFbsBitmap; + CleanupStack::PushL(targMask); + User::LeaveIfError(targMask->Create(targSize,EGray256)); + CFbsBitmapDevice* targMaskDevice = CFbsBitmapDevice::NewL(targMask); + CleanupStack::PushL(targMaskDevice); + CFbsBitGc* targMaskGc=NULL; + User::LeaveIfError(targMaskDevice->CreateContext(targMaskGc)); + CleanupStack::PushL(targMaskGc); +// + TPoint drawPos; + TRect testRect1(targSize); + iGc->Clear(); +// First we pre-stretch the source and mask bitmaps into temp bitmaps + targGc->DrawBitmap(TRect(targSize),srcBmp); + targMaskGc->DrawBitmap(TRect(targSize),srcMask); +// Then blend them onto the screen with a call to BitBltMasked + iGc->BitBltMasked(drawPos,targBmp,TRect(targSize),targMask,EFalse); + drawPos.iY+=targSize.iHeight; + TRect testRect2(drawPos,targSize); +// Next we combine the stretching and masking with one call to DrawBitmapMasked, +// this should give the same end result. + iGc->DrawBitmapMasked(testRect2,srcBmp,TRect(srcSize),srcMask,EFalse); + TRect testRect3; + if (alphaSupported) + { +// Finally if alpha blending supported we stretch and blend, again to achieve the exact same end result +// as the two previous calls. This was specificially done to catch DEF116427. + drawPos.iY+=targSize.iHeight; + testRect3=TRect(drawPos,targSize); + iGc->DrawBitmap(testRect3,srcAlpha); + } +//Use this just to check what we've put in the test bitmaps +/* + drawPos.iY+=targSize.iHeight+1; + iGc->BitBlt(drawPos,srcBmp); + drawPos.iY+=srcSize.iHeight+1; + iGc->BitBlt(drawPos,srcMask); + drawPos.iY+=srcSize.iHeight+1; + if (alphaSupported) + iGc->BitBlt(drawPos,srcAlpha); +*/ + iDevice->Update(); + TBool ret1=iDevice->RectCompare(testRect1,*iDevice,testRect2); + TBool ret2=alphaSupported?iDevice->RectCompare(testRect1,*iDevice,testRect3):ETrue; + if (!ret1 || !ret2) + { + INFO_PRINTF4(_L("DrawBitmapTest, ret1=%d, ret2=%d, Screen mode=%d"),ret1,ret2,aTestDisplayMode); + TEST(EFalse); + } + CleanupStack::PopAndDestroy(3,targMask); + CleanupStack::PopAndDestroy(3,targBmp); + } + CleanupStack::PopAndDestroy(3,srcMask); + CleanupStack::PopAndDestroy(3,srcAlpha); + CleanupStack::PopAndDestroy(3,srcBmp); + } + } + +//Tests alpha blending - for all display modes, some brush styles, user display modes, +//different positions on the screen. +void CTAlphaBlending::DoAlphaBlendingTestsL(const TPoint& aOrigin, + const TPoint& aDestPt, + const TRect& aSrcRc1, + const TPoint& aScrPt2, + const TPoint& aAlphaPt) + { + TBuf<128> buf; + _LIT(KLog,"Origin=(%d,%d) DestPt=(%d,%d) SrcRect=(%d,%d,%d,%d) ScrPt=(%d,%d) AlphaPt=(%d,%d)"); + buf.Format(KLog,aOrigin.iX,aOrigin.iY,aDestPt.iX,aDestPt.iY,aSrcRc1.iTl.iX,aSrcRc1.iTl.iY + ,aSrcRc1.iBr.iX,aSrcRc1.iBr.iY,aScrPt2.iX,aScrPt2.iY,aAlphaPt.iX,aAlphaPt.iY); + INFO_PRINTF1(buf); + TDisplayMode mode[] = {EColor16MA, EColor16MAP, EColor16MU, EColor16M, EColor256, EColor4K, EColor64K, + EGray256, EGray16, EGray4, EGray2, EColor16}; + CFbsBitmap* screenBmp = NULL; + CFbsBitmap* srcBmp = NULL; + CFbsBitmap* alphaBmp = NULL; + CGraphicsContext::TBrushStyle brushStyle[] = {CGraphicsContext::ENullBrush, CGraphicsContext::ESolidBrush}; + for(TInt i=0;iSetOrigin(aOrigin); + iGc->SetBrushStyle(brushStyle[j]); + TDisplayMode userDisplayMode[] = {EColor16MA, EColor16MAP, EColor16MU, EColor16M, EColor256, + EColor4K, EColor64K, EGray256, + EGray16, EGray4, EGray2, EColor16}; + for(TInt l=0;lSetUserDisplayMode(userDisplayMode[l]); + TSize scrDevSize = iDevice->SizeInPixels(); + TRect clipRc[] = {TRect(0, 0, scrDevSize.iWidth, scrDevSize.iHeight), + TRect(0, 1, scrDevSize.iWidth, scrDevSize.iHeight), // Tests Y clipping only + TRect(5, 0, scrDevSize.iWidth, scrDevSize.iHeight), // Tests X clipping only + TRect(5, 1, scrDevSize.iWidth, scrDevSize.iHeight), + TRect(3, 0, 14, 23)};//14 and 23 values are not accidental! + //Sometimes the method is called with aDestPt(13, 17). + for(TInt k=0;kClear(); + iGc->SetClippingRect(clipRc[k]); + DoAlphaBlendingTestL(screenBmp, srcBmp, alphaBmp, aDestPt, aSrcRc1, aScrPt2, aAlphaPt); + iGc->CancelClippingRect(); + } + }//end of - for(TInt l=0;lSetOrientation(CFbsBitGc::EGraphicsOrientationNormal); + } + DestroyAlphaBlendingBitmaps(screenBmp, srcBmp, alphaBmp); + }//end of - for(TInt j=0;jBitBltMasked() and iGc->AlphaBlendBitmaps(). +//To make that possible, aScreenBmp is copied to the screen before the call of +//iGc->BitBltMasked(). +void CTAlphaBlending::DoAlphaBlendingTestL(CFbsBitmap* aScreenBmp, + const CFbsBitmap* aSrcBmp, + const CFbsBitmap* aAlphaBmp, + const TPoint& aDestPt, + const TRect& aSrcRc1, + const TPoint& aSrcPt2, + const TPoint& aAlphaPt) + { + _LIT(KScreenBmpFile, "C:\\BMP_DATA.DAT"); + iGc->SetShadowMode(EFalse); + TInt i; + TInt res = -1; + TSize scrDevSize = iDevice->SizeInPixels(); + TInt allocatedSize = scrDevSize.iWidth * scrDevSize.iHeight * 2; + TRect screenBmpRc; + //The screen alpha blended data after calling of BitBltMasked() - will be filled after the call + TUint8* screenBmpDestData1 = new (ELeave) TUint8[allocatedSize]; + CleanupStack::PushL(screenBmpDestData1); + //The screen alpha blended data after calling of AlphaBlendingBitmaps() - will be filled after the call + TUint8* screenBmpDestData2 = new (ELeave) TUint8[allocatedSize]; + CleanupStack::PushL(screenBmpDestData2); + // Allow an effective restart of the test, since sometimes there are spurious + // InfoPrints that affect the comparisons. + for (TInt attempt = 0; res && (attempt < KMaximumAttempts); attempt++) + { + //Fill the blocks with some default value + Mem::Fill(screenBmpDestData1, allocatedSize, 0xCA); + Mem::Fill(screenBmpDestData2, allocatedSize, 0xCA); + //Check screen bitmap size + TSize screenBmpSize = aScreenBmp->SizeInPixels(); + if ((screenBmpSize.iWidth != KWidth) || (screenBmpSize.iHeight != KHeight)) + { + _LIT(KScreenErr,"DoAlphaBlendingTestL test: w:%d!=%d || h:%d!=%d"); + INFO_PRINTF5(KScreenErr, screenBmpSize.iWidth, KWidth, screenBmpSize.iHeight, KHeight); + TEST(EFalse); + } + // Alpha blending using CFbsBitGc::BitBltMasked // + if (iExtraLogging2) + { + _LIT(KLog1," CFbsBitGc::BitBltMasked test"); + INFO_PRINTF1(KLog1); + } + //Screen bitmap rectangle + screenBmpRc.SetRect(aDestPt, TSize(aSrcRc1.Width(), aSrcRc1.Height())); + + //Save screen bitmap + TInt saveAttempts = 5; + TInt err = aScreenBmp->Save(KScreenBmpFile); + while ((err != KErrNone) && saveAttempts--) + { + // Retry the save + _LIT(KSaveRetry,"DoAlphaBlendingTestL: Bitmap save failed, retrying."); + INFO_PRINTF1(KSaveRetry); + User::After(10000); + err = aScreenBmp->Save(KScreenBmpFile); + } + User::LeaveIfError(err); + + User::LeaveIfError(aScreenBmp->Resize(TSize(aSrcRc1.Width(), aSrcRc1.Height()))); + //Draw screen bitmap + iGc->Clear(); + iGc->SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha); + iGc->DrawBitmap(screenBmpRc, aScreenBmp); + iDevice->Update(); + //Do BitBltMasked() + iGc->BitBltMasked(aDestPt, aSrcBmp, aSrcRc1, aAlphaBmp, EFalse); + iDevice->Update(); + //Get screen data and write the data to screenBmpDestData1. + for(i=0;iGetScanLine(p, TPoint(0, i), scrDevSize.iWidth, EColor64K); + } + // Alpha blending using explicit form of CFbsBitGc::AlphaBlendBitmaps // + if (iExtraLogging2) + { + _LIT(KLog2," CFbsBitGc::AlphaBlendBitmaps explicit test"); + INFO_PRINTF1(KLog2); + } + //Clear screen + iGc->Clear(); + iDevice->Update(); + //Load screen bitmap + User::LeaveIfError(aScreenBmp->Load(KScreenBmpFile)); + //Do AlphaBlendBitmaps() + User::LeaveIfError(iGc->AlphaBlendBitmaps(aDestPt, aSrcBmp, aScreenBmp, aSrcRc1, + aSrcPt2, aAlphaBmp, aAlphaPt)); + iDevice->Update(); + //Get screen data and write the data to screenBmpDestData2. + for(i=0;iGetScanLine(p, TPoint(0, i), scrDevSize.iWidth, EColor64K); + } + //Compare screen bitmaps // + res = Mem::Compare(screenBmpDestData1, allocatedSize, screenBmpDestData2, allocatedSize); + + // colour comparison tolerance between RGB565 components. + const TInt KColourComparisonTolerance = 2; + if (res) + { + TBool testPassed = ETrue; + // strict byte-for-byte comparison of the pixel maps could have failed because blending algorithms may + // differ slightly, but actual resulting colours may be close enough + for (int byteNumber = 0; byteNumber < allocatedSize; byteNumber+=2) + { + // find any RGB565 value that doesn't match and examine each component + if ( *(TUint16*)(screenBmpDestData1 + byteNumber) != *(TUint16*)(screenBmpDestData2 + byteNumber)) + { + TUint16 Rgb1 = *(TUint16*)(screenBmpDestData1 + byteNumber); + TUint16 Rgb2 = *(TUint16*)(screenBmpDestData2 + byteNumber); + + TInt16 Red1 = (Rgb1 & 0xF800) >> 11; + TInt16 Red2 = (Rgb2 & 0xF800) >> 11; + TInt16 DiffRed = Abs(Red1 - Red2); + + TInt16 Green1 = (Rgb1 & 0x07E0) >> 5; + TInt16 Green2 = (Rgb2 & 0x07E0) >> 5; + TInt16 DiffGreen = Abs(Green1 - Green2); + + TInt16 Blue1 = (Rgb1 & 0x001F); + TInt16 Blue2 = (Rgb2 & 0x001F); + TInt16 DiffBlue = Abs(Blue1 - Blue2); + + // is any difference is outside the tolerance break out signaling test failure + if (DiffRed > KColourComparisonTolerance || + DiffGreen > KColourComparisonTolerance || + DiffBlue > KColourComparisonTolerance) + { + testPassed = EFalse; + break; + } + } + } + if (testPassed) + { + res = 0; + } + } + + if (res && (attempt < KMaximumAttempts - 1)) + { + INFO_PRINTF1(_L("Memory comparison 1 failed, retrying")); + // Skip to next attempt + continue; + } + TEST(res == 0); + + // Alpha blending using implicit form of CFbsBitGc::AlphaBlendBitmaps // + if (iExtraLogging2) + { + _LIT(KLog3," CFbsBitGc::AlphaBlendBitmaps implicit test"); + INFO_PRINTF1(KLog3); + } + //Clear screen + iGc->Clear(); + iDevice->Update(); + //Draw screen bitmap (it's already loaded) + User::LeaveIfError(aScreenBmp->Resize(TSize(aSrcRc1.Width(), aSrcRc1.Height()))); + iGc->SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha); + iGc->DrawBitmap(screenBmpRc, aScreenBmp); + iDevice->Update(); + //Do AlphaBlendBitmaps() + User::LeaveIfError(iGc->AlphaBlendBitmaps(aDestPt, aSrcBmp, aSrcRc1, aAlphaBmp, aSrcRc1.iTl)); + iDevice->Update(); + //Get screen data and write the data to screenBmpDestData2. + for(i=0;iGetScanLine(p, TPoint(0, i), scrDevSize.iWidth, EColor64K); + } + //Compare screen bitmaps // + if (iExtraLogging2) + { + _LIT(KLog4," Compare Screen Bitmaps"); + INFO_PRINTF1(KLog4); + } + res = Mem::Compare(screenBmpDestData1, allocatedSize, screenBmpDestData2, allocatedSize); + + if (res && (attempt < KMaximumAttempts - 1)) + { + INFO_PRINTF1(_L("Memory comparison 2 failed, retrying")); + } + + // Reload the screen bitmap as it was before: + User::LeaveIfError(aScreenBmp->Load(KScreenBmpFile)); + } + TEST(res == 0); + + //Destroy the allocated memory blocks + CleanupStack::PopAndDestroy(2);//screenBmpDestData1 & screenBmpDestData2 + } + +void CTAlphaBlending::CreateAlphaBlendingBitmapsLC(CFbsBitmap*& aScreenBmp, + CFbsBitmap*& aSrcBmp, + CFbsBitmap*& aAlphaBmp, + TDisplayMode aMode) + { + TInt i; + TSize size(KWidth, KHeight); + //The screen data + TUint8 screenBmpSrcData[KHeight][KWidth * 3 + 2] = // "+ 2" - every row is aligned to a 32 bit boundary + {//0 1 2 3 4 5 6 7 8 9 + {0x00, 0x00, 0x00, 0x20, 0x21, 0x22, 0x30, 0x31, 0x32, 0x40, 0x41, 0x42, 0x50, 0x51, 0x51, 0x60, 0x61, 0x62, 0x70, 0x71, 0x72, 0x80, 0x81, 0x82, 0x90, 0x91, 0x92, 0xA0, 0xA1, 0xA2, 0x00, 0x00}, + {0x19, 0x18, 0x17, 0x29, 0x28, 0x27, 0x39, 0x38, 0x37, 0x49, 0x48, 0x47, 0x59, 0x58, 0x57, 0x69, 0x68, 0x67, 0x79, 0x78, 0x77, 0x89, 0x88, 0x87, 0x99, 0x98, 0x97, 0xA9, 0xA8, 0xA7, 0x00, 0x00}, + {0x1F, 0x1E, 0x1D, 0x2F, 0x2E, 0x2D, 0x3F, 0x3E, 0x3D, 0x4F, 0x4E, 0x4D, 0x5F, 0x5E, 0x5D, 0x6F, 0x6E, 0x6D, 0x7F, 0x7E, 0x7D, 0x8F, 0x8E, 0x8D, 0x9F, 0x9E, 0x9D, 0xAF, 0xAE, 0xAD, 0x00, 0x00} + }; + //The source bitmap data + TUint8 srcBmpData[KHeight][KWidth * 3 + 2] = // "+ 2" - every row is aligned to a 32 bit boundary + {//0 1 2 3 4 5 6 7 8 9 + {0x32, 0x67, 0xA2, 0x11, 0x34, 0x67, 0xC5, 0xA3, 0x91, 0x01, 0xB3, 0xA8, 0xF3, 0x3F, 0x1E, 0x88, 0x11, 0x12, 0xAE, 0xEE, 0x9A, 0x56, 0x12, 0x81, 0xB4, 0xCA, 0x91, 0xFF, 0x1A, 0x2A, 0x00, 0x00}, + {0x02, 0xB1, 0xE2, 0xAA, 0xBB, 0x13, 0x22, 0xA8, 0xC3, 0x75, 0x8D, 0xFF, 0xA4, 0xAB, 0x00, 0xC5, 0xA6, 0x22, 0xBB, 0x09, 0xC1, 0x97, 0x25, 0xC6, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0x00, 0x00}, + {0x32, 0x50, 0x76, 0x27, 0xCC, 0x45, 0x81, 0xE5, 0xE9, 0xB7, 0xCD, 0x11, 0x32, 0xB1, 0x23, 0xFF, 0x71, 0x11, 0xCC, 0xAA, 0xF2, 0x98, 0x13, 0x8C, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00} + }; + //The alpha bitmap data + TUint8 alphaBmpData[KHeight][KWidth + 2] = // "+ 2" - every row is aligned to a 32 bit boundary + {//0 1 2 3 4 5 6 7 8 9 + {0x68, 0x68, 0x68, 0xAC, 0xD9, 0xB2, 0x8F, 0x11, 0xA0, 0xC1, 0x00, 0x00}, + {0x71, 0x5A, 0xF6, 0xEE, 0xF9, 0xE5, 0x06, 0x4C, 0xBB, 0x7B, 0x00, 0x00}, + {0x9F, 0x99, 0x45, 0x17, 0xA8, 0xF5, 0xFF, 0xD2, 0x22, 0x1D, 0x00, 0x00} + }; + + if(aMode == EColor16MU) + { + + TInt buffer_size = KWidth * 4 ; + TUint8* buffer = new(ELeave) TUint8[buffer_size]; + TPtr8 source_ptr(buffer, buffer_size, buffer_size); + + //Screen bitmap + aScreenBmp = new (ELeave) CFbsBitmap; + CleanupStack::PushL(aScreenBmp); + User::LeaveIfError(aScreenBmp->Create(size, aMode)); + for(i=0; iSetScanLine(source_ptr, i); + } + + //Source bitmap + aSrcBmp = new (ELeave) CFbsBitmap; + CleanupStack::PushL(aSrcBmp); + User::LeaveIfError(aSrcBmp->Create(size, aMode)); + for(i=0; iSetScanLine(source_ptr, i); + } + + + //Alpha bitmap + aAlphaBmp = new (ELeave) CFbsBitmap; + CleanupStack::PushL(aAlphaBmp); + User::LeaveIfError(aAlphaBmp->Create(size, EGray256)); + for(i=0;iSetScanLine(p, i); + } + + delete [] buffer; + } + else + { + //Screen bitmap + aScreenBmp = new (ELeave) CFbsBitmap; + CleanupStack::PushL(aScreenBmp); + User::LeaveIfError(aScreenBmp->Create(size, aMode)); + for(i=0;iSetScanLine(p, i); + } + //Source bitmap + aSrcBmp = new (ELeave) CFbsBitmap; + CleanupStack::PushL(aSrcBmp); + User::LeaveIfError(aSrcBmp->Create(size, aMode)); + for(i=0;iSetScanLine(p, i); + } + //Alpha bitmap + aAlphaBmp = new (ELeave) CFbsBitmap; + CleanupStack::PushL(aAlphaBmp); + User::LeaveIfError(aAlphaBmp->Create(size, EGray256)); + for(i=0;iSetScanLine(p, i); + } + } + } + +void CTAlphaBlending::DestroyAlphaBlendingBitmaps(CFbsBitmap*& aScreenBmp, + CFbsBitmap*& aSrcBmp, + CFbsBitmap*& aAlphaBmp) + { + CleanupStack::PopAndDestroy(aAlphaBmp); + aAlphaBmp = NULL; + CleanupStack::PopAndDestroy(aSrcBmp); + aSrcBmp = NULL; + CleanupStack::PopAndDestroy(aScreenBmp); + aScreenBmp = NULL; + } + +//The test doesn't check anything. It is for debugging only. +void CTAlphaBlending::TestAlphaBlending2L() + { + static const TDisplayMode modeList[] = { + EColor64K, EColor256, EColor16MAP, EColor16MA, EColor16MU, EColor4K + }; + const TInt KNumTestDisplayModes=sizeof(modeList)/sizeof(modeList[0]); + for(TInt orientation=0;orientation<=CFbsBitGc::EGraphicsOrientationRotated270;orientation++) + { + CFbsBitmap* srcBmp = NULL; + CFbsBitmap* alphaBmp = NULL; + TInt err = KErrNotSupported; + // Try several modes + for (TInt modeIndex = 0; (err != KErrNone) && modeIndex < KNumTestDisplayModes; modeIndex++) + { + err = CreateScreenDevice(modeList[modeIndex],(CFbsBitGc::TGraphicsOrientation)orientation); + } + if (err == KErrNotSupported) + { + // Orientation not supported, try next one + continue; + } + TInt j; + //The source bitmap data + TUint8 srcBmpData[100]; + for(j=0;j<100;j++) + { + srcBmpData[j] = 0xAA; + } + //The alpha bitmap data + TUint8 alphaBmpData[20]; + for(j=0;j<20;j++) + { + alphaBmpData[j] = TUint8(j); + } + //Source bitmap + srcBmp = new (ELeave) CFbsBitmap; + CleanupStack::PushL(srcBmp); + User::LeaveIfError(srcBmp->Create(TSize(100, 1), EColor256)); + TPtr8 p1(srcBmpData, 100, 100); + srcBmp->SetScanLine(p1, 0); + //Alpha bitmap + alphaBmp = new (ELeave) CFbsBitmap; + CleanupStack::PushL(alphaBmp); + User::LeaveIfError(alphaBmp->Create(TSize(20, 1), EGray256)); + TPtr8 p2(alphaBmpData, 20, 20); + alphaBmp->SetScanLine(p2, 0); + //Do BitBltMasked() + iGc->BitBltMasked(TPoint(20, 20), srcBmp, TRect(10, 0, 100, 1), alphaBmp, EFalse); + iDevice->Update(); + iGc->SetOrientation(CFbsBitGc::EGraphicsOrientationNormal); + // + CleanupStack::PopAndDestroy(alphaBmp); + CleanupStack::PopAndDestroy(srcBmp); + } + } + +TUint32 AlphaBlend(TUint32 aDestPixel, TUint32 aSrcPixel, TUint8 aMask) + { + TUint32 dr = (aDestPixel & 0x00FF0000) >> 16; + TUint32 dg = (aDestPixel & 0x0000FF00) >> 8; + TUint32 db = aDestPixel & 0x000000FF; + + TUint32 sr = (aSrcPixel & 0x00FF0000) >> 16; + TUint32 sg = (aSrcPixel & 0x0000FF00) >> 8; + TUint32 sb = aSrcPixel & 0x000000FF; + + TUint32 rr = (aMask * sr)/255 + ((0xFF - aMask) * dr)/255; + TUint32 rg = (aMask * sg)/255 + ((0xFF - aMask) * dg)/255; + TUint32 rb = (aMask * sb)/255 + ((0xFF - aMask) * db)/255; + + return(rr << 16 | rg << 8 | rb | 0xff000000); + } + +inline TUint32 OptimizedBlend32(TInt aPrimaryRed,TInt aPrimaryGreen,TInt aPrimaryBlue,TUint32 aSecondary,TUint8 aAlphaValue) + { + + if(aAlphaValue == 0xff) + { + return (aPrimaryBlue + (aPrimaryGreen<<8) + (aPrimaryRed<<16)) | 0xff000000; + } + else + { + const TUint32 alphaValue = (aAlphaValue << 8) + aAlphaValue; + + const TInt r2 = (aSecondary & 0x00ff0000) >> 16; + const TInt g2 = (aSecondary & 0x0000ff00) >> 8; + const TInt b2 = aSecondary & 0x000000ff; + + const TInt r3 = ((alphaValue * (aPrimaryRed - r2)) >> 16) + r2; + const TInt g3 = ((alphaValue * (aPrimaryGreen - g2)) >> 16) + g2; + const TInt b3 = ((alphaValue * (aPrimaryBlue - b2)) >> 16) + b2; + + return (b3 & 0xFF) | ((g3<<8) & 0xFF00) | ((r3<<16) & 0xFF0000) | 0xFF000000; + } + } + + +/** + @SYMTestCaseID GRAPHICS-BITGDI-0085 + + @SYMDEF + + @SYMTestCaseDesc + + @SYMTestPriority High + + @SYMTestStatus Implemented + + @SYMTestActions + + @SYMTestExpectedResults +*/ +// This tests the correctness of the results of alpha-blending with EColor16MA +void CTAlphaBlending::TestAlphaBlendCorrect(TDisplayMode /* aScreenMode */, TDisplayMode /* aBitmapMode */) + { + // test data + TUint32 top = 0xFFCCEE55; + TUint32 beneath = 0xFFEEAA66; + TUint8 alpha = 0xF0; + + TInt maxDiff = 0; + + for(TInt i = 0; i < 100000; i++) + { + top = Math::Random(); + beneath = Math::Random(); + alpha = Math::Random(); + TUint32 res1 = AlphaBlend(beneath, top, alpha); + TUint32 res2 = OptimizedBlend32((top >> 16) & 0xFF,(top >>8) & 0xFF,(top & 0xFF),beneath, alpha); + + if(res1 != res2) + { + TInt diff = 0; + TInt diff1 = res1 & 0xFF; + TInt diff2 = res2 & 0xFF; + + diff = diff1 - diff2; + + if(diff < 0) + diff*=-1; + + if(diff > maxDiff) + maxDiff = diff; + + diff1 = (res1 >> 8) & 0xFF; + diff2 = (res2 >> 8) & 0xFF; + + diff = diff1 - diff2; + + if(diff < 0) + diff*=-1; + + if(diff > maxDiff) + maxDiff = diff; + + + diff1 = (res1 >> 16) & 0xFF; + diff2 = (res2 >> 16) & 0xFF; + + diff = diff1 - diff2; + + if(diff < 0) + diff*=-1; + + if(diff > maxDiff) + maxDiff = diff; + + } + } + + INFO_PRINTF1(_L("Results:")); + + if(maxDiff) + INFO_PRINTF2(_L("Max Diff = %i"), maxDiff); + else + INFO_PRINTF1(_L("Results are identical")); + } + +//-------------- +__CONSTRUCT_STEP__(AlphaBlending) + +void CTAlphaBlendingStep::TestSetupL() + { + } +