diff -r 433cbbb6a04b -r 10534483575f uiacceltk/hitchcock/Client/src/alfdrawer.cpp --- a/uiacceltk/hitchcock/Client/src/alfdrawer.cpp Fri Mar 12 15:47:04 2010 +0200 +++ b/uiacceltk/hitchcock/Client/src/alfdrawer.cpp Mon Mar 15 12:43:37 2010 +0200 @@ -19,10 +19,13 @@ #include +#include #include "alfcrppluginclient.h" +#include "alflogger.h" #include #include +#include // Class to hold internal alf drawer data. NONSHARABLE_CLASS( CAlfDrawer::TAlfDrawerData ) @@ -39,6 +42,59 @@ // Creates CAlfCrpPluginClient instance. static CAlfCrpPluginClient* CreateAlfCrpClientL(); +/** + * Misc utility methods for CAlfDrawer. + */ +NONSHARABLE_CLASS(AlfDrawerUtils) + { +public: + + enum TRotation + { + ERotationNone, + ERotation90, + ERotation180, + ERotation270 + }; + + /** + * Inverse rotate. + */ + static void RotateBack(TInt aVirtualRotation, TRect& aRect, TSize aScreenSize) + { + if( aVirtualRotation == ERotation90 || aVirtualRotation == ERotation270 ) + { + RotateRect( aVirtualRotation, aRect, aScreenSize, ETrue ); + } + else if( aVirtualRotation == ERotation180 ) + { + RotateRect( aVirtualRotation, aRect, aScreenSize, EFalse ); + } + } + + /** + * Rotate rect + */ + static void RotateRect(TInt aDirection, TRect& aRect, TSize aScreenSize, TBool aMirror) + { + if (aMirror) aDirection = (aDirection+2)%4; // magic + for (;aDirection > 0; aDirection--) + { + TSize rotatedSize(aRect.Size().iHeight, aRect.Size().iWidth); + aRect = TRect(TPoint(aRect.iTl.iY, aScreenSize.iWidth - aRect.iTl.iX - rotatedSize.iHeight ), rotatedSize); + aScreenSize = TSize(aScreenSize.iHeight, aScreenSize.iWidth); + } + } + + /** + * Copies screen to bitmap using 'read pixels' operation. + */ + static void DoCopyScreenToBitmapL( + CWsScreenDevice& aDevice, + CFbsBitmap* aBitmap, + const TRect& aRect ); + + }; // --------------------------------------------------------------------------- // NewL @@ -92,6 +148,304 @@ } // --------------------------------------------------------------------------- +// FallbackCopyScreenToBitmap +// --------------------------------------------------------------------------- +// +EXPORT_C TInt CAlfDrawer::FallbackCopyScreenToBitmap( + CWsScreenDevice& aDevice, + CFbsBitmap* aBitmap, + const TRect& aRect) + { + TRAPD(err, AlfDrawerUtils::DoCopyScreenToBitmapL(aDevice, aBitmap, aRect)); + return err; + } + +// --------------------------------------------------------------------------- +// DoCopyScreenToBitmapL +// --------------------------------------------------------------------------- +// +void AlfDrawerUtils::DoCopyScreenToBitmapL( + CWsScreenDevice& aDevice, + CFbsBitmap* aBitmap, + const TRect& aRect ) + { + if (aDevice.GetScreenNumber() != 0) // only screen 0 supported for now + { + User::Leave(KErrNotSupported); + } + + if ( !aBitmap || + !aBitmap->Handle() || + aBitmap->IsCompressedInRAM() || + aBitmap->ExtendedBitmapType() != KNullUid ) + { + User::Leave(KErrArgument); + } + + __ALFLOGSTRING("DoCopyScreenToBitmapL begin"); + + RAlfDirectClient client; + CleanupClosePushL(client); + + // Get size & virtual rotation from ALF side. + // GetSizeAndRotation will also create session to server. + + TInt rotation = 0; + TSize size; + User::LeaveIfError(client.GetSizeAndRotation(size, rotation)); + + // Calculate device size in pixels (same as aDevice.SizeInPixels()) + TSize deviceSize = size; + if (rotation == AlfDrawerUtils::ERotation90 || + rotation == AlfDrawerUtils::ERotation270 ) + { + deviceSize.iWidth = size.iHeight; + deviceSize.iHeight = size.iWidth; + } + + // Clip aRect to screen boundaries + TRect actualRect(deviceSize); + actualRect.Intersection(aRect); + + __ALFLOGSTRING2("DoCopyScreenToBitmapL - requested rect origin %d x %d", actualRect.iTl.iX, actualRect.iTl.iY ) ; + __ALFLOGSTRING2("DoCopyScreenToBitmapL - requested rect %d x %d", actualRect.Size().iWidth, actualRect.Size().iHeight ) ; + __ALFLOGSTRING2("DoCopyScreenToBitmapL - bitmap rect %d x %d", aBitmap->SizeInPixels().iWidth, aBitmap->SizeInPixels().iHeight ); + __ALFLOGSTRING1("DoCopyScreenToBitmapL - bitmap mode %d", aBitmap->DisplayMode() ); + + if ( TRect( aBitmap->SizeInPixels() ).IsEmpty() || + actualRect.IsEmpty() ) + { + __ALFLOGSTRING("DoCopyScreenToBitmapL - empty rect or zero bitmap size"); + CleanupStack::PopAndDestroy(); // CleanupClosePushL + return; + } + + // Select display mode. + + TDisplayMode surfaceDisplayMode = EColor64K; + TDisplayMode bitmapDisplayMode = aBitmap->DisplayMode(); + if ( bitmapDisplayMode == EColor16MU || + bitmapDisplayMode == EColor16MA || + bitmapDisplayMode == EColor16MAP ) + { + surfaceDisplayMode = bitmapDisplayMode; + } + + __ALFLOGSTRING3("DoCopyScreenToBitmapL - surface size %d x %d, mode %d", + size.iWidth, size.iHeight, surfaceDisplayMode ) ; + + // Read pixels to temporary bitmap + CFbsBitmap* surfaceBitmap = new (ELeave) CFbsBitmap; + CleanupStack::PushL( surfaceBitmap ); + User::LeaveIfError( surfaceBitmap->Create( size, surfaceDisplayMode ) ); + + TInt err = client.ReadPixels( surfaceBitmap->Handle() ); + __ALFLOGSTRING1("DoCopyScreenToBitmapL - ReadPixels returned %d", err); + User::LeaveIfError( err ); + + // Copy data + TInt surfaceStride = CFbsBitmap::ScanLineLength(size.iWidth, surfaceDisplayMode); + __ALFLOGSTRING2("DoCopyScreenToBitmapL - DisplayMode %d, Stride %d", surfaceDisplayMode, surfaceStride); + + TDisplayMode displayMode = surfaceDisplayMode; + + TInt8 bytesPerPixel = 2; + switch( displayMode ) + { + case EColor64K: + { + bytesPerPixel = 2; + break; + } + case EColor16MU: + case EColor16MA: + case EColor16MAP: + { + bytesPerPixel = 4; + break; + } + + default: + { + __ALFLOGSTRING1("DoCopyScreenToBitmapL - display mode not supported %d", displayMode); + User::Leave( KErrNotSupported ); + } + } + + // actualRect (/aRect) must be converted to correct coordinate system. + TRect surfaceRect(actualRect); + AlfDrawerUtils::RotateBack(rotation, surfaceRect, deviceSize); + surfaceRect.Intersection(TRect(size)); + + __ALFLOGSTRING2("DoCopyScreenToBitmapL - surface rect tl %d x %d", surfaceRect.iTl.iX, surfaceRect.iTl.iY ) ; + __ALFLOGSTRING2("DoCopyScreenToBitmapL - surface rect size %d x %d", surfaceRect.Size().iWidth, surfaceRect.Size().iHeight ) ; + + CFbsBitmap* bitmap = NULL; + TBool needTempBitmap = ETrue; + + if( aBitmap->DisplayMode() == displayMode && actualRect == aRect && aBitmap->SizeInPixels() == aRect.Size() ) + { + // Copy data direcly to given bitmap + bitmap = aBitmap; + needTempBitmap = EFalse; + } + else + { + // Create temporary bitmap which maches the sufrace's pixel format and source rect size + bitmap = new (ELeave) CFbsBitmap; + CleanupStack::PushL( bitmap ); + TInt err = bitmap->Create( actualRect.Size(), displayMode ); + __ALFLOGSTRING1("DoCopyScreenToBitmapL - Create returned %d", err ); + User::LeaveIfError( err ); + __ALFLOGSTRING("DoCopyScreenToBitmapL - display mode or size don't mach -> using temp bitmap" ); + } + + surfaceBitmap->BeginDataAccess(); + bitmap->BeginDataAccess(); + + TUint8* surfacePtr = (TUint8*)surfaceBitmap->DataAddress() + surfaceStride * surfaceRect.iTl.iY; + + TUint8* bitmapPtr = (TUint8*)bitmap->DataAddress(); + TInt rowBegin = surfaceRect.iTl.iX * bytesPerPixel; + TInt captureBitmapWidth = surfaceRect.Width() * bytesPerPixel; + + const TSize bitmapSize = bitmap->SizeInPixels(); + + // Initialize with direct copy case parameters + TInt bitmapPtrColumnDelta = bytesPerPixel; + TInt bitmapPtrRowDelta = bitmap->DataStride(); + + const TSize surfaceRectSize(surfaceRect.Size()); + if ( rotation == AlfDrawerUtils::ERotationNone ) + { + __ALFLOGSTRING("DoCopyScreenToBitmapL - direct copy") ; + + // Direct copy case + for ( TInt row = surfaceRectSize.iHeight - 1 ; row >= 0 ; --row ) + { + // Copy only the desired part of the bitmap + memcpy( bitmapPtr, + surfacePtr + rowBegin, + captureBitmapWidth ); + surfacePtr += surfaceStride; + bitmapPtr += bitmap->DataStride(); + } + } + else + { + // Handle rotation cases + // + // 0 degree case + // A B C + // 1 2 3 + // 90 degrees anti-clockwise + // C 3 + // B 2 + // A 1 + // 180 degrees anti-clockwise + // 3 2 1 + // C B A + // 270 degrees anti-clockwise + // 1 A + // 2 B + // 3 C + // + switch (rotation) + { + case AlfDrawerUtils::ERotation90: + bitmapPtrColumnDelta = -bitmap->DataStride(); + bitmapPtrRowDelta = bytesPerPixel; + bitmapPtr += ( bitmapSize.iHeight - 1 ) * bitmap->DataStride(); + break; + case AlfDrawerUtils::ERotation180: + bitmapPtrColumnDelta = -bytesPerPixel; + bitmapPtrRowDelta = -bitmap->DataStride(); + bitmapPtr += ( bitmapSize.iHeight - 1 ) * bitmap->DataStride() + ( bitmapSize.iWidth - 1 ) * bytesPerPixel; + break; + case AlfDrawerUtils::ERotation270: + bitmapPtrColumnDelta = bitmap->DataStride(); + bitmapPtrRowDelta = -bytesPerPixel; + bitmapPtr += ( bitmapSize.iWidth - 1 ) * bytesPerPixel; + break; + default: + break; + } + + // We go through surface row by row, column by column and + // copy pixel data to appropriate place to bitmap + if ( bytesPerPixel == 4 ) + { + __ALFLOGSTRING("DoCopyScreenToBitmapL - four bytes per pixel, rotated copy") ; + + for ( TInt row = surfaceRectSize.iHeight - 1 ; row >= 0 ; --row ) + { + TUint8* rowBitmapPtr = bitmapPtr; + TUint8* rowSurfacePtr = surfacePtr + rowBegin; + for ( TInt column = surfaceRectSize.iWidth - 1 ; column >= 0 ; --column ) + { + *((TUint32*)rowBitmapPtr) = *((TUint32*)rowSurfacePtr); + + rowBitmapPtr += bitmapPtrColumnDelta; + rowSurfacePtr += bytesPerPixel; + } + + surfacePtr += surfaceStride; + bitmapPtr += bitmapPtrRowDelta; + } + } + else + { + // Now bytesPerPixel == 2 + __ALFLOGSTRING("DoCopyScreenToBitmapL - two bytes per pixel, rotated copy") ; + for ( TInt row = surfaceRectSize.iHeight - 1 ; row >= 0 ; --row ) + { + TUint8* rowBitmapPtr = bitmapPtr; + TUint8* rowSurfacePtr = surfacePtr + rowBegin; + for ( TInt column = surfaceRectSize.iWidth - 1 ; column >= 0 ; --column ) + { + *((TUint16*)rowBitmapPtr) = *((TUint16*)rowSurfacePtr); + + rowBitmapPtr += bitmapPtrColumnDelta; + rowSurfacePtr += bytesPerPixel; + } + + surfacePtr += surfaceStride; + bitmapPtr += bitmapPtrRowDelta; + } + } + } + __ALFLOGSTRING("DoCopyScreenToBitmapL - copy finished" ); + surfaceBitmap->EndDataAccess(ETrue); + bitmap->EndDataAccess(); + + if( !needTempBitmap ) + { + bitmap = NULL; + } + else // bitblit the temporary bitmap to given bitmap + { + CFbsBitmapDevice* tempBitmapDevice = CFbsBitmapDevice::NewL( aBitmap ); + CleanupStack::PushL( tempBitmapDevice ); + CFbsBitGc* tempBitmapGc = NULL; + User::LeaveIfError( tempBitmapDevice->CreateContext( tempBitmapGc ) ); + CleanupStack::PushL( tempBitmapGc ); + + tempBitmapGc->SetDrawMode( CGraphicsContext::EDrawModeWriteAlpha ); + tempBitmapGc->BitBlt( TPoint(), bitmap ); + + CleanupStack::PopAndDestroy( tempBitmapGc ); + CleanupStack::PopAndDestroy( tempBitmapDevice ); + CleanupStack::PopAndDestroy( bitmap ); + } + + CleanupStack::PopAndDestroy( surfaceBitmap ); + + CleanupStack::PopAndDestroy(); // CleanupClosePushL + + __ALFLOGSTRING("DoCopyScreenToBitmapL - Done"); + } + +// --------------------------------------------------------------------------- // Constructor // --------------------------------------------------------------------------- //