imagehandlingutilities/thumbnailmanager/thumbnailserver/src/thumbnailgeneratetask.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 00:23:15 +0200
changeset 1 235a7fc86938
parent 0 2014ca87e772
child 5 82749d516180
child 14 2edacbf5d3f9
permissions -rw-r--r--
Revision: 201003 Kit: 201005

/*
* Copyright (c) 2006-2007 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:  Task for generating new thumbnails
 *
*/


#include <e32base.h>
#include <fbs.h>

#include <thumbnailmanager.h>

#include "thumbnailgeneratetask.h"
#include "thumbnailscaletask.h"
#include "thumbnailprovider.h"
#include "thumbnailserver.h"
#include "thumbnailtaskprocessor.h"
#include "thumbnailmanagerconstants.h"
#include "thumbnaillog.h"
#include "thumbnailpanic.h"

// ======== MEMBER FUNCTIONS ========

// ---------------------------------------------------------------------------
// CThumbnailGenerateTask::CThumbnailGenerateTask()
// C++ default constructor can NOT contain any code, that might leave.
// ---------------------------------------------------------------------------
//
CThumbnailGenerateTask::CThumbnailGenerateTask( CThumbnailTaskProcessor&
    aProcessor, CThumbnailServer& aServer, RFile64* aFile, TDesC8* aBuffer,
    const TDataType* aMimeType, CThumbnailManager::TThumbnailFlags aFlags,
    const TSize& aSize, TDisplayMode aDisplayMode, TInt aPriority,
    RArray < TThumbnailPersistentSize >* aMissingSizes, const TDesC& aTargetUri,
    TThumbnailSize aThumbnailSize, const TThumbnailId aThumbnailId, 
    const CThumbnailManager::TThumbnailQualityPreference aQualityPreference ): 
    CThumbnailTask( aProcessor, aPriority ), iServer( aServer ), 
    iFlags( aFlags ), iSize( aSize ), iDisplayMode( aDisplayMode ),
    iMissingSizes( aMissingSizes ), iTargetUri( aTargetUri ),
    iThumbnailSize( aThumbnailSize ), iThumbnailId(aThumbnailId),
    iQualityPreference( aQualityPreference )
    {
    TN_DEBUG2( "CThumbnailGenerateTask(0x%08x)::CThumbnailGenerateTask()", this);
    
    if ( !aBuffer && aFile)
        {
        iFile = *aFile; 
        iFile.FullName( iFilename );
        }
    else if( aBuffer )
        {
        iBuffer = aBuffer;
        }
    if ( aMimeType )
        {
        iMimeType = *aMimeType;
        }
    else
        {
        iMimeType = TDataType(KNullDesC8);
        }
    
    // scaled bitmaps to pool by default
    iScaledBitmapToPool = ETrue;
    }


// ---------------------------------------------------------------------------
// CThumbnailGenerateTask::~CThumbnailGenerateTask()
// Destructor.
// ---------------------------------------------------------------------------
//
CThumbnailGenerateTask::~CThumbnailGenerateTask()
    {
    TN_DEBUG2("CThumbnailGenerateTask(0x%08x)::~CThumbnailGenerateTask()", this);
    
    if ( iProvider )
        {
        iProvider->CancelGetThumbnail();
        }
	
    if ( iMissingSizes )
        {
        iMissingSizes->Reset();
        delete iMissingSizes;
        }
		
    if ( iBitmap )
        {
        iServer.DeleteBitmapFromPool( iBitmap->Handle());
        iBitmap = NULL;
        }
		
    iProvider = NULL;
    delete iBuffer;
    iBuffer = NULL;
    
    iFile.Close();
    TN_DEBUG1("CThumbnailGenerateTask::~CThumbnailGenerateTask() - file handle closed");
    }


// ---------------------------------------------------------------------------
// CThumbnailGenerateTask::StartL()
// ---------------------------------------------------------------------------
//
void CThumbnailGenerateTask::StartL()
    {
    TN_DEBUG2( "CThumbnailGenerateTask(0x%08x)::StartL()", this );

    CThumbnailTask::StartL();
    
#ifdef _DEBUG
    aStart.UniversalTime();
#endif

      
    TParsePtrC parse(iFilename);
    TPtrC ext(parse.Ext());
    TBuf8< KMaxDataTypeLength > mimeType;                
    if  (ext.CompareF(KNonEmbeddedArtExt)== 0) 
        {       
        mimeType.Copy( KImageMime );  		
        }
    else
        {
        mimeType = iMimeType.Des8();
        }
    iProvider = iServer.ResolveProviderL(mimeType);
       	
    TN_DEBUG3( "CThumbnailGenerateTask(0x%08x) -- provider UID 0x%08x", this,
        iProvider->Uid());

    __ASSERT_DEBUG(( iProvider ), ThumbnailPanic( EThumbnailNullPointer ));

    iProvider->CancelGetThumbnail();
    iProvider->Reset();
    iProvider->SetObserver( *this );

    TSize effectiveTargetSize;
    TSize croppedTargetSize;

    CalculateTargetSizesL( effectiveTargetSize, croppedTargetSize );

    iProvider->SetTargetSize( effectiveTargetSize );
      
    if(effectiveTargetSize == TSize())
        {
        iProvider->SetTargetSize( croppedTargetSize );
        }
		
    if ( !iBuffer )
        {
        iProvider->GetThumbnailL( iServer.Fs(), iFile, iMimeType, iFlags,
            iDisplayMode, iQualityPreference );
        }
    else
        {
        iProvider->GetThumbnailL( iServer.Fs(), iBuffer, iMimeType, iFlags,
            iDisplayMode, iQualityPreference );
        }
    }


// ---------------------------------------------------------------------------
// CThumbnailGenerateTask::RunL()
// ---------------------------------------------------------------------------
//
void CThumbnailGenerateTask::RunL()
    {
    // No implementation required
    }


// ---------------------------------------------------------------------------
// CThumbnailGenerateTask::DoCancel()
// ---------------------------------------------------------------------------
//
void CThumbnailGenerateTask::DoCancel()
    {
    TN_DEBUG2( "CThumbnailGenerateTask(0x%08x)::DoCancel()", this );
    if ( iProvider )
        {
        iProvider->CancelGetThumbnail();
        }
    }


// ---------------------------------------------------------------------------
// Calculate the largest non-cropped size and largest cropped size and
// let the provider plug-in know the values
// ---------------------------------------------------------------------------
//
void CThumbnailGenerateTask::CalculateTargetSizesL( TSize& aEffectiveTargetSize,
    TSize& aCroppedTargetSize )
    { 
    if ( iThumbnailSize == ECustomThumbnailSize )
        {
        if ( iFlags& CThumbnailManager::ECropToAspectRatio )
            {
            aCroppedTargetSize = iSize;
            }
        else
            {
            aEffectiveTargetSize = iSize;
            }       
        }
    
    if ( iThumbnailSize != ECustomThumbnailSize )
        {
        RArray < TThumbnailPersistentSize > sizes = iServer.PersistentSizesL();
        const TInt count = sizes.Count();
        for ( TInt i = 0; i < count; i++ )
            {
            TThumbnailPersistentSize size( sizes[i] );     

            iSize = size.iSize;
            if ( size.iCrop )
               {
               aCroppedTargetSize.iWidth = Max( aCroppedTargetSize.iWidth,
                   size.iSize.iWidth );
               aCroppedTargetSize.iHeight = Max( aCroppedTargetSize.iHeight,
                   size.iSize.iHeight );
               if(iBuffer)
                 {
                 iFlags = ( CThumbnailManager::TThumbnailFlags ) (iFlags | CThumbnailManager::ECropToAspectRatio);
                 aEffectiveTargetSize = aCroppedTargetSize;
                 }
               }
            else
               {
                aEffectiveTargetSize.iWidth = Max( aEffectiveTargetSize.iWidth,
                   size.iSize.iWidth );
                aEffectiveTargetSize.iHeight = Max( aEffectiveTargetSize.iHeight,
                   size.iSize.iHeight );
               }
            
            if(size.iType == iThumbnailSize)
              {
              break;
              }     
            }
        }    
    }

// ---------------------------------------------------------------------------
// Thumbnail provider observer callback to notify the server when
// thumbnail has been generated.
// ---------------------------------------------------------------------------
//
void CThumbnailGenerateTask::ThumbnailProviderReady( const TInt aError,
    CFbsBitmap* aBitmap, const TSize& aOriginalSize, const TBool aEXIF, const TBool aPortrait )
    {
    TN_DEBUG4( 
        "CThumbnailGenerateTask(0x%08x)::ThumbnailProviderReady(aError=%d, aBitmap=0x%08x)", this, aError, aBitmap );

    #ifdef _DEBUG
    aStop.UniversalTime();
    TN_DEBUG2( "CThumbnailGenerateTask::ThumbnailProviderReady() generate took %d ms", (TInt)aStop.MicroSecondsFrom(aStart).Int64()/1000);
    #endif
    
    iPortrait = aPortrait;
    iEXIF = aEXIF;
    iOriginalSize = aOriginalSize;

    if ( aError )
        {
        delete aBitmap;
        aBitmap = NULL;
        // Create a temporary bitmap of size 1 for storing blacklisted thumbnail
        // Because no actual bitmap data is generated, there is no reason to 
        // add bitmap to server bitmap pool. Completion of client request with
        // error code just results in applications showing their default bitmap. 
        if( iFilename != KNullDesC || iTargetUri != KNullDesC )
            {
            if ( aError == KErrNotSupported ||
                    aError == KErrCorrupt ||
                    aError == KErrCompletion)
                {
                TRAPD( err, CreateBlackListedL( aOriginalSize ) );
                if (err != KErrNone)
                    {
                    TN_DEBUG2( "CThumbnailGenerateTask::ThumbnailProviderReady() - blacklisting failed with code %d", err );
                    }
                }
            }
        Complete( aError );
        }
    else
        {
        // CreateScaleTasksL will take ownership of bitmap
        
#ifdef _DEBUG
        TN_DEBUG2( "CThumbnailGenerateTask::ThumbnailProviderReady() - displaymode is %d", aBitmap->DisplayMode());
#endif
        
        TRAPD( err, CreateScaleTasksL( aBitmap ));
        aBitmap = NULL;
        // If CreateScaleTasksL left, we are responsible for completing
        // the RMessage. If there was no leave, then this call will not
        // complete actual the message, just the mark the task as completed.
        Complete( err );
        }
    }


// ---------------------------------------------------------------------------
// Create tasks to scale the thumbnail to each persistent thumbnail size
// and also to the size the client requested
// ---------------------------------------------------------------------------
//
void CThumbnailGenerateTask::CreateScaleTasksL( CFbsBitmap* aBitmap )
    {
    __ASSERT_DEBUG(( aBitmap ), ThumbnailPanic( EThumbnailNullPointer ));

    CleanupStack::PushL( aBitmap );
    iServer.AddBitmapToPoolL( iRequestId.iSession, aBitmap );

    // Keep pointer so we can delete bitmap from pool
    iBitmap = aBitmap;
    CleanupStack::Pop( aBitmap );

    // compTask is the scale task which returns the bitmap to the client
    CThumbnailScaleTask* complTask = NULL;
	
    if ( iMissingSizes )
        {
        const TInt count = iMissingSizes->Count();
        
        for ( TInt i( 0 ); i < count; i++ )
            {
            TThumbnailSize size = (*iMissingSizes)[ i ].iType;
#ifdef _DEBUG
            TN_DEBUG3( "CThumbnailGenerateTask(0x%08x)::CreateScaleTasksL() *iMissingSizes)[ i ].iType == %d", this, size );
#endif
            
            if ( iPortrait )
                {
                if ( size == EFullScreenThumbnailSize ||
                     size == EVideoFullScreenThumbnailSize ||
                     size == EAudioFullScreenThumbnailSize ||
                     size == EImageFullScreenThumbnailSize )
                    {
                    TN_DEBUG2( "*iMissingSizes)[ i ].iWidth == %d", (*iMissingSizes)[ i ].iSize.iWidth );
                    TN_DEBUG2( "*iMissingSizes)[ i ].iHeight == %d", (*iMissingSizes)[ i ].iSize.iHeight );
                    TInt width = (*iMissingSizes)[ i ].iSize.iWidth; 
                    (*iMissingSizes)[ i ].iSize.iWidth = (*iMissingSizes)[ i ].iSize.iHeight;
                    (*iMissingSizes)[ i ].iSize.iHeight = width;
                    TN_DEBUG2( "*iMissingSizes)[ i ].iWidth == %d", (*iMissingSizes)[ i ].iSize.iWidth );
                    TN_DEBUG2( "*iMissingSizes)[ i ].iHeight == %d", (*iMissingSizes)[ i ].iSize.iHeight );
                    }
                }
            
            CThumbnailScaleTask* scaleTask = CThumbnailScaleTask::NewL( iProcessor, iServer, iFilename,
                iBitmap, iOriginalSize, (*iMissingSizes)[ i ].iSize, (*iMissingSizes)[ i ].iCrop, iDisplayMode,
                KMaxPriority, iTargetUri, (*iMissingSizes)[ i ].iType, iThumbnailId, iScaledBitmapToPool, iEXIF );
            CleanupStack::PushL( scaleTask );
            
            TInt err1 = KErrNone;
            TInt err2 = KErrNone;
            if(iFilename != KNullDesC)
                {
                TRAP(err1, iServer.StoreForPathL(iFilename));
                }
            if(iTargetUri != KNullDesC)
                {
                TRAP(err2, iServer.StoreForPathL(iTargetUri));
                }
            // if trying to access Z drive, don't try to store
            // don't want to store custom sizes
            if( err1 == KErrAccessDenied || err2 == KErrAccessDenied ||
                    (*iMissingSizes)[ i ].iType == ECustomThumbnailSize || 
                    (*iMissingSizes)[ i ].iType == EUnknownThumbnailSize )
                {
                scaleTask->SetDoStore( EFalse );
                TN_DEBUG2( "CThumbnailGenerateTask(0x%08x)::CreateScaleTasksL() - do not store", this );
                }
            else
                {
                scaleTask->SetDoStore( ETrue );
                }
            
            iProcessor.AddTaskL( scaleTask );
            CleanupStack::Pop( scaleTask );
            
            // completion to first task, because task processor works like stack
            if( i == 0 )
                {
                // compTask is now responsible for completing the RMessage
                scaleTask->SetMessageData( iRequestId, iMessage );
                ResetMessageData();
                }
            }
        }
    else
        {
        if( iPortrait )
            {
            if ( iThumbnailSize == EFullScreenThumbnailSize ||
                 iThumbnailSize == EVideoFullScreenThumbnailSize ||
                 iThumbnailSize == EAudioFullScreenThumbnailSize ||
                 iThumbnailSize == EImageFullScreenThumbnailSize )
                      {
                      TInt width = iSize.iWidth; 
                      iSize.iWidth = iSize.iHeight;
                      iSize.iHeight = width;
                      }
            }
        
        complTask = CThumbnailScaleTask::NewL( iProcessor, iServer, iFilename,
            iBitmap, iOriginalSize, iSize, iFlags& CThumbnailManager
            ::ECropToAspectRatio, iDisplayMode, KMaxPriority, iTargetUri,
            iThumbnailSize, iThumbnailId, iScaledBitmapToPool, iEXIF );
        CleanupStack::PushL( complTask );
        
        TInt err1 = KErrNone;
        TInt err2 = KErrNone;
        if(iFilename != KNullDesC)
            {
            TRAP(err1, iServer.StoreForPathL(iFilename));
            }
        if(iTargetUri != KNullDesC)
            {
            TRAP(err2, iServer.StoreForPathL(iTargetUri));
            }
        // if trying to access Z drive, don't try to store
        // don't want to store custom sizes
        if( err1 == KErrAccessDenied || err2 == KErrAccessDenied ||
            iThumbnailSize == ECustomThumbnailSize || 
            iThumbnailSize == EUnknownThumbnailSize )
            {
            complTask->SetDoStore( EFalse );
            TN_DEBUG2( "CThumbnailGenerateTask(0x%08x)::CreateScaleTasksL() - do not store", this );
            }
        else
            {
            complTask->SetDoStore( ETrue );
            }
        
        iProcessor.AddTaskL( complTask );
        CleanupStack::Pop( complTask );
        
        // compTask is now responsible for completing the RMessage and
        // returning the bitmap to the client
        complTask->SetMessageData( iRequestId, iMessage );
        ResetMessageData();
        }

    // Scale tasks now reference the bitmap in the pool
    iServer.DeleteBitmapFromPool( iBitmap->Handle());
    iBitmap = NULL;
    }

// ---------------------------------------------------------------------------
// Defines if scaled bitmaps need to be added to pool
// ---------------------------------------------------------------------------
//
void CThumbnailGenerateTask::ScaledBitmapToPool( TBool aBool )
    {
    iScaledBitmapToPool = aBool;
    }

// ---------------------------------------------------------------------------
// Stores a blacklisted thumbnail
// ---------------------------------------------------------------------------
//
void CThumbnailGenerateTask::CreateBlackListedL( const TSize& aOriginalSize )
    {
    CFbsBitmap* tempBitmap = 0;
    tempBitmap = new (ELeave) CFbsBitmap();
    CleanupStack::PushL( tempBitmap );
    TSize tempSize( 1, 1 );
    User::LeaveIfError( tempBitmap->Create( tempSize, iDisplayMode ) );
    
    // Instead of creating a blacklisted entry of requested size (iThumbnailSize) in thumbnail db,
    // consider blacklisting all sizes (hence the changes are needed in thumbnail fetching logic too).
    // However, decoding of source to thumnail could succeed in other sizes, which makes blacklisting
    // of requested size only meaningful. 
    if(iFilename != KNullDesC)
        {
        iServer.StoreForPathL( iFilename )->StoreThumbnailL( 
            iFilename, tempBitmap, aOriginalSize, EFalse, iThumbnailSize, iThumbnailId, EFalse, ETrue );
        }
    else if(iTargetUri != KNullDesC)
        {
        iServer.StoreForPathL( iTargetUri )->StoreThumbnailL( 
            iTargetUri, tempBitmap, aOriginalSize, EFalse, iThumbnailSize, iThumbnailId, EFalse, ETrue );
        }

    CleanupStack::PopAndDestroy( tempBitmap );
    }