idlehomescreen/widgetmanager/src/wmimageconverter.cpp
branchRCL_3
changeset 11 ff572dfe6d86
parent 5 c743ef5928ba
child 12 9674c1a575e9
--- a/idlehomescreen/widgetmanager/src/wmimageconverter.cpp	Fri Feb 19 22:42:37 2010 +0200
+++ b/idlehomescreen/widgetmanager/src/wmimageconverter.cpp	Fri Mar 12 15:41:49 2010 +0200
@@ -200,12 +200,11 @@
     {
     CFbsBitmap* bitmap = NULL;
     CFbsBitmap* mask = NULL;
-    
+   
+   
     if ( aUid.iUid >= KWidgetUidLowerBound &&
        aUid.iUid < KWidgetUidUpperBound  )
         {
-        // AknsUtils::CreateAppIconLC panics incase of WRT
-
         RApaLsSession lsSession;
         User::LeaveIfError( lsSession.Connect() );
         CleanupClosePushL( lsSession );
@@ -214,42 +213,53 @@
         CArrayFixFlat<TSize>* sizeArray = new (ELeave)
             CArrayFixFlat<TSize>( KAppSizeArraySize );
         CleanupStack::PushL( sizeArray );
+
         User::LeaveIfError( lsSession.GetAppIconSizes( aUid, *sizeArray ) );
-        TSize size;
+        
+        // there should be atleast one size available
+        if ( sizeArray->Count() == 0 ){ User::Leave( KErrNotReady ); };
+        
+        TSize size(0,0);
         for( TInt i=0; i < sizeArray->Count(); i++ )
             {
-            size = (*sizeArray)[i];
-            if ( size == iSize )
-                {
-                break;
-                }
+            TSize s = (*sizeArray)[i];
+            if ( size.iWidth < s.iWidth || size.iHeight < s.iHeight )
+                { size = s; }
+            if ( size == iSize ) { break; }
             }
+
         CApaMaskedBitmap* maskedBmp = CApaMaskedBitmap::NewLC();
         User::LeaveIfError( lsSession.GetAppIcon( aUid, size, *maskedBmp ) );
-        iBitmap = static_cast<CFbsBitmap*>( maskedBmp );  // ownership transfered
         
-        iMask = new ( ELeave ) CFbsBitmap;
-        User::LeaveIfError( iMask->Create( 
-                                    maskedBmp->Mask()->SizeInPixels(), 
-                                    maskedBmp->Mask()->DisplayMode() ) );
-        // duplicate mask, origional is owned by maskedBmp
-        iMask->Duplicate( maskedBmp->Mask()->Handle() );
-        CleanupStack::Pop( maskedBmp );
-        maskedBmp = NULL;
-        CleanupStack::PopAndDestroy(sizeArray); 
+        // handle bitmap
+        iBitmap = new ( ELeave ) CFbsBitmap;
+        User::LeaveIfError( iBitmap->Create( 
+                maskedBmp->SizeInPixels(), 
+                maskedBmp->DisplayMode() ) );
+
+        // scale bitmap
+        ScaleBitmapL( iSize, iBitmap, maskedBmp );  
+
+        // handle mask
+        if ( maskedBmp->Mask() )
+            {
+            iMask = new ( ELeave ) CFbsBitmap;
+            User::LeaveIfError( iMask->Create( 
+                    maskedBmp->Mask()->SizeInPixels(), 
+                    maskedBmp->Mask()->DisplayMode() ) );
+            
+            // scale mask
+            ScaleBitmapL( iSize, iMask, maskedBmp->Mask() );
+            }
+        
+        // cleanup
+        CleanupStack::PopAndDestroy( maskedBmp );
+        CleanupStack::PopAndDestroy( sizeArray ); 
         CleanupStack::PopAndDestroy( &lsSession );
-
-        // scale or notify
-        if ( size == iSize )
-            {
-            iState = EIdle;
-            iObserver->NotifyCompletion( KErrNone );
-            }
-        else
-            {
-            iScaleNeeded = ETrue;
-            ScaleBitmap( iSize.iWidth, iSize.iHeight );
-            }
+        
+        // notify
+        iState = EIdle;
+        iObserver->NotifyCompletion( KErrNone );
         }
     else if ( aUid.iUid != KNullUid.iUid )
         {
@@ -398,7 +408,7 @@
     
     iMask = new (ELeave) CFbsBitmap();
     iMask->Create( size, EGray256 ); 
-    
+
     if ( size != iSize )
         {
         iScaleNeeded = ETrue;
@@ -933,6 +943,283 @@
     }
 
 // ---------------------------------------------------------------------------
+// CWmImageConverter::DoesScaleBitmapUseFallBack
+// ---------------------------------------------------------------------------
+//
+TBool CWmImageConverter::DoesScaleBitmapUseFallBack( CFbsBitmap* aSrcBitmap )
+    {
+    if ( !aSrcBitmap )
+        {
+        return EFalse;
+        }
+
+    TDisplayMode displayMode = aSrcBitmap->DisplayMode();
+    TBool fallbackOnly = EFalse;
+
+    switch ( displayMode )
+        {
+        case EGray2:
+        case EGray4:
+        case EGray16:
+        case EColor16:
+        case EColor16M:
+        case ERgb:
+        case EColor16MA:
+            fallbackOnly = ETrue;
+            break;
+        case EGray256:
+        case EColor4K:
+        case EColor64K:
+        case EColor256:
+        case EColor16MU:
+            // These are the supported modes
+            break;
+        default:
+            fallbackOnly = ETrue;
+        }
+
+    return fallbackOnly;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CWmImageConverter::ScaleBitmapL
+// ---------------------------------------------------------------------------
+//
+void CWmImageConverter::ScaleBitmapL( 
+                            const TSize& aSize,
+                            CFbsBitmap* aTrgBitmap,
+                            CFbsBitmap* aSrcBitmap )
+    {
+    if ( !aSrcBitmap ) User::Leave( KErrArgument );
+    if ( !aTrgBitmap ) User::Leave( KErrArgument );
+    if ( aSrcBitmap->DisplayMode() != aTrgBitmap->DisplayMode() )
+        {
+        User::Leave( KErrArgument );
+        }
+    
+    TRect targetRect( aSize );
+
+    // calculate aspect ratio
+    TInt srcHeight = aSrcBitmap->SizeInPixels().iHeight;
+    TInt srcWidth = aSrcBitmap->SizeInPixels().iWidth;
+    TReal scaleRatio( 1 ); //no scale as defaul
+    
+    //If any dimension is 0, then we do not bother to scale
+    if ( targetRect.Width() > 0 && targetRect.Height() > 0 )
+        {
+        TReal xRatio = ( ( TReal )srcWidth / ( TReal )targetRect.Width() );
+        TReal yRatio = ( ( TReal )srcHeight / ( TReal )targetRect.Height() );
+        //Find out appropriate scaling factor
+        xRatio > yRatio ? ( scaleRatio = xRatio ) : ( scaleRatio = yRatio );
+        }
+
+    //Scale the size for target bitmap
+    targetRect.SetHeight( srcHeight / scaleRatio );
+    targetRect.SetWidth( srcWidth / scaleRatio );    
+    
+    TSize trgBitmapSize = aTrgBitmap->SizeInPixels();
+    
+    // calculate the valid drawing area
+    TRect drawRect = targetRect;
+    drawRect.Intersection( TRect( TPoint( 0, 0 ), trgBitmapSize ) );
+
+    if( drawRect.IsEmpty() || 
+        aSrcBitmap->SizeInPixels().iHeight <= 0 || 
+        aSrcBitmap->SizeInPixels().iWidth <= 0 )
+        {
+        User::Leave( KErrArgument );
+        }
+
+    TSize srcSize = aSrcBitmap->SizeInPixels();
+
+    TBool srcTemporary = EFalse;
+    if ( aSrcBitmap->IsRomBitmap() )
+        {
+        srcTemporary = ETrue;
+        }
+
+    TDisplayMode displayMode = aSrcBitmap->DisplayMode();
+    TBool fallbackOnly = DoesScaleBitmapUseFallBack( aSrcBitmap );
+
+    if ( fallbackOnly )
+        {
+        CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL( aTrgBitmap );
+        CleanupStack::PushL( dev );
+        CFbsBitGc* gc = NULL;
+        User::LeaveIfError( dev->CreateContext( gc ) );
+        CleanupStack::PushL( gc );
+
+        // write alpha information if it exists
+        if ( aSrcBitmap->DisplayMode() == EColor16MA )
+            {
+            gc->SetDrawMode( CGraphicsContext::EDrawModeWriteAlpha );
+            }
+
+        // targetRect is used because DrawBitmap handles clipping automatically
+        gc->DrawBitmap( targetRect, aSrcBitmap );
+        CleanupStack::PopAndDestroy( 2 ); // dev, gc
+        return;
+        }
+
+    // Heap lock for FBServ large chunk to prevent background
+    // compression of aSrcBitmap after if IsCompressedInRAM returns EFalse
+    aSrcBitmap->LockHeapLC( ETrue ); // fbsheaplock
+    TBool fbsHeapLock = ETrue;
+    if ( aSrcBitmap->IsCompressedInRAM() )
+        {
+        srcTemporary = ETrue;
+        }
+
+    CFbsBitmap* realSource = aSrcBitmap;
+    if ( srcTemporary )
+        {
+        CleanupStack::PopAndDestroy(); // fbsheaplock
+        fbsHeapLock = EFalse;
+
+        realSource = new ( ELeave ) CFbsBitmap();
+        CleanupStack::PushL( realSource );
+        User::LeaveIfError(
+            realSource->Create( srcSize, aSrcBitmap->DisplayMode() ) );
+        CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL( realSource );
+        CleanupStack::PushL( dev );
+        CFbsBitGc* gc = NULL;
+        User::LeaveIfError( dev->CreateContext( gc ) );
+        CleanupStack::PushL( gc );
+        gc->BitBlt( TPoint( 0, 0 ), aSrcBitmap );
+        CleanupStack::PopAndDestroy( 2 ); // dev, gc
+        }
+
+    if ( !fbsHeapLock )
+        {
+        // Heap lock for FBServ large chunk is only needed with large bitmaps.
+        if ( realSource->IsLargeBitmap() || aTrgBitmap->IsLargeBitmap() )
+            {
+            aTrgBitmap->LockHeapLC( ETrue ); // fbsheaplock
+            }
+        else
+            {
+            CleanupStack::PushL( ( TAny* )NULL );
+            }
+        }
+
+    TUint32* srcAddress = realSource->DataAddress();
+    TUint32* trgAddress = aTrgBitmap->DataAddress();
+
+    const TInt xSkip = ( srcSize.iWidth << 8 ) / targetRect.Width();
+    const TInt ySkip = ( srcSize.iHeight << 8 ) / targetRect.Height();
+
+    const TInt drawWidth  = drawRect.Width();
+    const TInt drawHeight = drawRect.Height();
+
+    TRect offsetRect( targetRect.iTl, drawRect.iTl );
+    const TInt yPosOffset = ySkip * offsetRect.Height();
+    const TInt xPosOffset = xSkip * offsetRect.Width();
+
+    if ( ( displayMode == EGray256 ) || ( displayMode == EColor256 ) )
+        {
+        TInt srcScanLen8 = CFbsBitmap::ScanLineLength(
+            srcSize.iWidth, displayMode );
+        TInt trgScanLen8 = CFbsBitmap::ScanLineLength(
+            trgBitmapSize.iWidth, displayMode );
+
+        TUint8* trgAddress8 = reinterpret_cast< TUint8* >( trgAddress );
+
+        TInt yPos = yPosOffset;
+        // skip left and top margins in the beginning
+        trgAddress8 += trgScanLen8 * drawRect.iTl.iY + drawRect.iTl.iX;
+
+        for ( TInt y = 0; y < drawHeight; y++ )
+            {
+            TUint8* srcAddress8 = reinterpret_cast< TUint8* >( srcAddress ) +
+                ( srcScanLen8 * ( yPos >> 8 ) );
+
+            TInt xPos = xPosOffset;
+            for ( TInt x = 0; x < drawWidth; x++ )
+                {
+                *( trgAddress8++ ) = srcAddress8[xPos >> 8];
+                xPos += xSkip;
+                }
+
+            yPos += ySkip;
+
+            trgAddress8 += trgScanLen8 - drawWidth;
+            }
+        }
+    else if ( displayMode == EColor4K || displayMode == EColor64K )
+        {
+        TInt srcScanLen16 = CFbsBitmap::ScanLineLength(
+            srcSize.iWidth, displayMode ) /2;
+        TInt trgScanLen16 = CFbsBitmap::ScanLineLength(
+            trgBitmapSize.iWidth, displayMode ) /2;
+
+        TUint16* trgAddress16 = reinterpret_cast< TUint16* >( trgAddress );
+
+        TInt yPos = yPosOffset;
+        // skip left and top margins in the beginning
+        trgAddress16 += trgScanLen16 * drawRect.iTl.iY + drawRect.iTl.iX;
+
+        for ( TInt y = 0; y < drawHeight; y++ )
+            {
+            TUint16* srcAddress16 = reinterpret_cast< TUint16* >( srcAddress ) +
+                ( srcScanLen16 * ( yPos >> 8 ) );
+
+            TInt xPos = xPosOffset;
+            for ( TInt x = 0; x < drawWidth; x++ )
+                {
+                *( trgAddress16++ ) = srcAddress16[xPos >> 8];
+                xPos += xSkip;
+                }
+
+            yPos += ySkip;
+
+            trgAddress16 += trgScanLen16 - drawWidth;
+            }
+        }
+    else if ( displayMode == EColor16MU )
+        {
+        TInt srcScanLen32 = CFbsBitmap::ScanLineLength(
+            srcSize.iWidth, displayMode ) /4;
+        TInt trgScanLen32 = CFbsBitmap::ScanLineLength(
+            trgBitmapSize.iWidth, displayMode ) /4;
+
+        TUint32* trgAddress32 = reinterpret_cast< TUint32* >( trgAddress );
+
+        TInt yPos = yPosOffset;
+        // skip left and top margins in the beginning
+        trgAddress32 += trgScanLen32 * drawRect.iTl.iY + drawRect.iTl.iX;
+
+        for ( TInt y = 0; y < drawHeight; y++ )
+            {
+            TUint32* srcAddress32 = reinterpret_cast< TUint32* >( srcAddress ) +
+                ( srcScanLen32 * ( yPos >> 8 ) );
+
+            TInt xPos = xPosOffset;
+            for ( TInt x = 0; x < drawWidth; x++ )
+                {
+                *( trgAddress32++ ) = srcAddress32[xPos >> 8];
+                xPos += xSkip;
+                }
+
+            yPos += ySkip;
+
+            trgAddress32 += trgScanLen32 - drawWidth;
+            }
+        }
+    else
+        {
+        User::Leave( KErrUnknown );
+        }
+
+    CleanupStack::PopAndDestroy(); // fbsheaplock
+
+    if ( srcTemporary )
+        {
+        CleanupStack::PopAndDestroy(); // realSource
+        }
+    }
+
+// ---------------------------------------------------------------------------
 // CWmImageConverter::Finished
 // ---------------------------------------------------------------------------
 //