--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/uiacceltk/hitchcock/coretoolkit/src/HuiTextureManager.cpp Tue Feb 02 07:56:43 2010 +0200
@@ -0,0 +1,2505 @@
+/*
+* 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: Implementation of CHuiTextureManager, texture objects loading
+* and management.
+*
+*/
+
+
+
+#include <eikenv.h>
+#include <eikappui.h>
+#include <eikapp.h>
+
+#include "uiacceltk/HuiTextureManager.h" // Class definition
+#include "uiacceltk/HuiTextureProcessor.h"
+#include "HuiRenderPlugin.h"
+#include "uiacceltk/HuiEnv.h"
+#include "uiacceltk/HuiTexture.h"
+#include "uiacceltk/HuiFont.h"
+#include "uiacceltk/HuiUtil.h"
+#include "uiacceltk/HuiPanic.h"
+#include "uiacceltk/HuiDisplay.h"
+#include "huitextureanimationstate.h"
+
+/**
+ * Granularity of CHuiTextureManager::iAnimations and
+ * CHuiTextureManager::iAnimatedTextureGroupItems arrays.
+ */
+const TInt KHuiAnimationsGranularity = 4;
+
+EXPORT_C MHuiBitmapProvider::~MHuiBitmapProvider()
+ {
+ }
+
+EXPORT_C CHuiTextureManager::CHuiTextureManager(CHuiEnv& aEnv)
+ : CActive(EPriorityHigh),
+ iEnv(aEnv), iState(EIdle), iReleaseState(ENormal), iFS(CHuiStatic::FsSession()),
+ iAnimatedTextureGroupItems( KHuiAnimationsGranularity ),
+ iAnimations( KHuiAnimationsGranularity ),
+ iEnableTexMemCalculation( EFalse ) //Texture memory calculation is disabled by default
+ {}
+
+
+EXPORT_C void CHuiTextureManager::BaseConstructL()
+ {
+ iEnv.SetTextureManager(*this);
+
+ SetImagePathL(_L(""));
+
+ // Create a small initial bitmaps for decoder output.
+ iBitmap = new (ELeave) CFbsBitmap();
+ User::LeaveIfError( iBitmap->Create(TSize(4, 4), EColor64K) );
+ iMaskBitmap = new (ELeave) CFbsBitmap();
+ User::LeaveIfError( iMaskBitmap->Create(TSize(4, 4), EGray256) );
+
+ // Create blank texture
+ iBlankTexture = CHuiStatic::Renderer().CreateTextureL();
+ iBlankTexture->SetImageFileNameL(_L("blank"));
+
+ CActiveScheduler::Add(this);
+
+ // Enabling logging will cause diagnostics and debugging messages to be
+ // printed to a file.
+ CHuiStatic::EnableLogging(EFalse);
+ }
+
+
+EXPORT_C CHuiTextureManager::~CHuiTextureManager()
+ {
+ Cancel();
+
+ delete iAnimationWithoutGroup;
+ iAnimatedTextureGroupItems.Close();
+ iAnimations.ResetAndDestroy();
+ iAnimations.Close();
+
+ // Delete the texture processor.
+ delete iProcessor;
+
+ // Clear any remaining entries in the load queue.
+ for(TInt i = 0; i < iLoadQueue.Count(); ++i)
+ {
+ delete iLoadQueue[i].iDecoder;
+ iLoadQueue[i].iDecoder = 0;
+ }
+ iLoadQueue.Reset();
+
+ delete iBlankTexture;
+
+ // Remove all texture entries (from last to first -order)
+ /*while (iTextures.Count()>0)*/
+ for(TInt i = iTextures.Count()-1; i >= 0; --i)
+ {
+ CTextureEntry * te = iTextures[i];
+
+ if (te->iTexture)
+ {
+ delete te->iTexture;
+ }
+ else
+ {
+ // This texture was defined but never loaded.
+ HUI_DEBUG2(_L("CHuiTextureManager::~CHuiTextureManager() - Notice, texture id %i (\"%S\") was never loaded!"), te->iId, te->iFileName);
+ }
+ }
+
+ iTextures.ResetAndDestroy();
+ iStateObservers.Close();
+ iLoadObservers.Close();
+ iAnimatedTextures.Close();
+ iTextureAutoSizeObservers.Close();
+
+ delete iBitmap;
+ delete iMaskBitmap;
+ delete iImagePath;
+ }
+
+
+EXPORT_C CHuiEnv& CHuiTextureManager::Env()
+ {
+ return iEnv;
+ }
+
+
+EXPORT_C CHuiTexture* CHuiTextureManager::Texture(TInt aId)
+ {
+ TInt index = CheckTexture(aId);
+ if(index == -1)
+ {
+ HUI_DEBUG1(_L("CHuiTextureManager::Texture() - Texture id %i not found! Returning blank."), aId);
+ // NOTE: there is a danger of editing the blank texture
+ // instead of the real texture..
+ return &BlankTexture();
+ }
+ CHuiTexture * texture = iTextures[index]->iTexture;
+ if(texture)
+ {
+ return texture;
+ }
+ else
+ {
+ HUI_ASSERT(EFalse); // texture exists but is not loaded! (defined but not loaded)
+ return &BlankTexture();
+ }
+ }
+
+
+EXPORT_C const CHuiTexture* CHuiTextureManager::Texture(TInt aId) const
+ {
+ TInt id = CheckTexture(aId);
+ if(id == -1)
+ {
+ return &BlankTexture();
+ }
+ const CHuiTexture * texture = iTextures[id]->iTexture;
+ if(texture)
+ {
+ return texture;
+ }
+ else
+ {
+ HUI_ASSERT(EFalse); // texture exists but is not loaded! (defined but not loaded)
+ return &BlankTexture();
+ }
+ }
+
+
+EXPORT_C CHuiTexture* CHuiTextureManager::TextureL(TInt aId)
+ {
+ // try to get the index for the texture id
+ TInt index = CheckTexture(aId);
+ if(index != -1)
+ {
+ // If the texture has content and a filename, we can do a load-on-demand.
+ if(!iTextures[index]->iTexture->HasContent() && iTextures[index]->iFileName)
+ {
+ // we don't want to return textures without content
+ // so load-on-demand
+
+ // texture has an entry but the
+ // actual texture object has not been loaded yet
+
+ // we can load the texture if there's a filename
+ // available for this id
+ return &LoadTextureL(aId);
+ }
+
+ // texture found
+ return iTextures[index]->iTexture;
+ }
+
+ User::Leave(KErrNotFound);
+ return NULL; // never
+ }
+
+
+EXPORT_C void CHuiTextureManager::SetImagePathL(const TDesC& aPath)
+ {
+ delete iImagePath;
+ iImagePath = NULL;
+
+ TParsePtrC parse(aPath);
+ CEikonEnv* coe = CEikonEnv::Static();
+ if (aPath.Length() && !parse.DrivePresent() && coe && coe->EikAppUi() && coe->EikAppUi()->Application())
+ {
+ iImagePath = HBufC::NewL(aPath.Size()+2); // two extra characters for drive
+ TPtr ptr = iImagePath->Des();
+ ptr.Append(coe->EikAppUi()->Application()->AppFullName().Left(2));
+ ptr.Append(aPath);
+ }
+ else
+ {
+ iImagePath = aPath.AllocL();
+ }
+ }
+
+EXPORT_C const TDesC& CHuiTextureManager::ImagePath() const
+ {
+ return *iImagePath;
+ }
+
+
+EXPORT_C const CHuiTexture& CHuiTextureManager::BlankTexture() const
+ {
+ HUI_ASSERT(iBlankTexture!=NULL); // this MUST have a valid pointer otherwise access violation will follow..
+ return *iBlankTexture;
+ }
+
+
+EXPORT_C CHuiTexture& CHuiTextureManager::BlankTexture()
+ {
+ HUI_ASSERT(iBlankTexture!=NULL); // this MUST have a valid pointer otherwise access violation will follow..
+ return *iBlankTexture;
+ }
+
+
+EXPORT_C TBool CHuiTextureManager::SetTextureId(CHuiTexture* aTexture, TInt aId)
+ {
+
+ if(!aTexture)
+ {
+ // Cannot set texture ID for null texture.
+ return EFalse;
+ }
+
+ // Iterate through all the managed textures to find the one we
+ // are interested in, and then set its texture ID.
+ for(TInt i = 0; i < iTextures.Count(); ++i)
+ {
+ if(iTextures[i]->iTexture == aTexture)
+ {
+ // Texture was found in the list, so set the new identifier.
+ iTextures[i]->iId = aId;
+ return ETrue;
+ }
+ }
+
+ // Texture was not found in the manager's list.
+ return EFalse;
+ }
+
+EXPORT_C TBool CHuiTextureManager::IsLoaded(const CHuiTexture * texture) const
+ {
+ if(texture != NULL && texture->HasContent() && !IsInLoadQueue(texture))
+ {
+ return ETrue;
+ }
+ return EFalse;
+ }
+
+
+EXPORT_C TBool CHuiTextureManager::IsLoaded(const TDesC& aImageName, const TInt aFrameNumber) const
+ {
+ TFileName fileName = *iImagePath;
+ fileName.Append(aImageName);
+ TInt index = CheckTexture(fileName, aFrameNumber);
+ if(index < 0)
+ {
+ HUI_DEBUG1(_L("CHuiTextureManager::IsLoaded() - Texture \"%S\" was not found. Assuming not loaded."), &aImageName);
+ return EFalse;
+ }
+ return IsLoaded(iTextures[index]->iTexture);
+ }
+
+
+EXPORT_C TBool CHuiTextureManager::IsLoaded(TInt aId) const
+ {
+ HUI_ASSERT(aId!=0);
+ TInt index = CheckTexture(aId);
+ if(index < 0)
+ {
+ HUI_DEBUG1(_L("CHuiTextureManager::IsLoaded() - Texture having id %i was not found. Assuming not loaded."), aId);
+ return EFalse;
+ }
+ return IsLoaded(iTextures[index]->iTexture);
+ }
+
+
+EXPORT_C void CHuiTextureManager::AppendTextureL(CHuiTexture* aTexture, TInt aId)
+ {
+ // Panic if the manager is currently restoring or releasing textures.
+ if(iReleaseState == EReleasing)
+ {
+ THuiPanic::Panic(THuiPanic::ETextureManagerTextureDestroyedDuringRelease);
+ }
+ else if(iReleaseState == ERestoring)
+ {
+ THuiPanic::Panic(THuiPanic::ETextureManagerTextureConstructedDuringRestore);
+ }
+ else
+ {
+ // for PC lint
+ }
+
+ HUI_ASSERT(aTexture != NULL);
+
+#ifdef _DEBUG
+ // Look for an existing entry for this.
+ // There must not be any duplicates present!
+ for(TInt i = 0; i < iTextures.Count(); ++i)
+ {
+ if(iTextures[i]->iTexture == aTexture)
+ {
+ User::Leave(KErrAlreadyExists);
+ }
+ }
+#endif
+
+ // Create a new texture entry
+ CTextureEntry * te = new (ELeave) CTextureEntry(aId, aTexture);
+ CleanupStack::PushL(te);
+ // Add the new entry to the list of new textures
+ User::LeaveIfError( iTextures.Append(te) );
+ CleanupStack::Pop(); // pop the texture entry
+
+ HUI_DEBUG1(_L("CHuiTextureManager::AppendTextureL() - Registered texture 0x%x."), aTexture);
+ }
+
+
+EXPORT_C void CHuiTextureManager::RemoveTexture(CHuiTexture& aTexture)
+ {
+ // Panic if the manager is currently restoring or releasing textures.
+ if(iReleaseState == EReleasing)
+ {
+ THuiPanic::Panic(THuiPanic::ETextureManagerTextureDestroyedDuringRelease);
+ }
+ else if(iReleaseState == ERestoring)
+ {
+ THuiPanic::Panic(THuiPanic::ETextureManagerTextureDestroyedDuringRestore);
+ }
+ else
+ {
+ // for PC lint
+ }
+
+ // Cancel loading of the texture to be removed.
+ CancelLoadingOfTexture(aTexture);
+
+ // Manual sequential search.
+ for(TInt index = iTextures.Count() - 1; index >= 0; --index)
+ {
+ if(iTextures[index]->iTexture == &aTexture)
+ {
+ CTextureEntry * entry = iTextures[index];
+ if ( entry->iFileName )
+ {
+ HUI_DEBUG4(_L("CHuiTextureManager::RemoveTexture() - Removing texture 0x%x (Name: \"%S\", Id: %i). Number of textures after deleting: %i."),
+ &aTexture, &(aTexture.ImageFileName()), entry->iId, iTextures.Count()-1);
+ }
+ else
+ {
+ HUI_DEBUG3(_L("CHuiTextureManager::RemoveTexture() - Removing unnamed texture 0x%x ( Id: %i). Number of textures after deleting: %i."),
+ &aTexture, entry->iId, iTextures.Count()-1);
+ }
+
+ iTextures.Remove(index);
+ delete entry;
+ return;
+ }
+ }
+
+ HUI_DEBUG2(_L("CHuiTextureManager::RemoveTexture() - Error! Failed to remove texture 0x%x \"%S\". Texture not found."), &aTexture, &aTexture.ImageFileName());
+ // this is a programming error.. texturemanager is aware of all textures in the toolkit!!
+ #ifdef _DEBUG
+ HUI_PANIC(THuiPanic::ETextureNotValid)
+ #endif
+ }
+
+
+EXPORT_C CHuiTexture& CHuiTextureManager::LoadTextureL(
+ const TDesC& aImageName,
+ THuiTextureUploadFlags aFlags,
+ TInt aId,
+ TInt aFrameNumber)
+ {
+ return LoadTextureL(aImageName, TSize(0, 0), aFlags, aId, aFrameNumber);
+ }
+
+
+EXPORT_C CHuiTexture& CHuiTextureManager::LoadTextureL(const TInt aId,
+ const TSize& aTextureMaxSize,
+ THuiTextureUploadFlags aFlags)
+ {
+ return LoadTextureL(KNullDesC(), aTextureMaxSize, aFlags, aId);
+ }
+
+
+EXPORT_C CHuiTexture& CHuiTextureManager::LoadTextureL(const TDesC& aImageName,
+ const TSize& aTextureMaxSize,
+ THuiTextureUploadFlags aFlags,
+ TInt aId,
+ TInt aFrameNumber)
+ {
+ // Ignore EHuiTextureFlagAllowDirectBitmapUsage flag
+ aFlags = (THuiTextureUploadFlags)(aFlags & ~EHuiTextureFlagAllowDirectBitmapUsage);
+
+ TFileName fileName;
+
+ CTextureEntry * entry = NULL;
+
+ // If the name is invalid, and there was no filename available
+ // based on id, return a dummy texture.
+ if((aImageName.Length() == 0) && (aId == 0))
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::LoadTextureL() - No filename or id provided for texture. Returning blank."));
+ return BlankTexture();
+ }
+
+ // add path to filename if filename has been passed
+ if(aImageName.Length() > 0)
+ {
+ // assume relative pathname and prepend the image path to get full filename
+ fileName = aImageName;
+ PrependImagePath(fileName);
+ }
+
+ // if no name has been passed as a parameter but
+ // a nonzero id has been passed, we
+ // can assume that there's a predefined name available
+ if((aImageName.Length() == 0) && (aId != 0))
+ {
+ // search for a texture filename based on the id.
+ TInt index = CheckTexture(aId);
+ if(index >=0)
+ {
+ entry = iTextures[index];
+ HUI_ASSERT(entry->iFileName);
+ fileName = *(entry->iFileName);
+ }
+ else
+ {
+ HUI_DEBUG1(_L("CHuiTextureManager::LoadTextureL() - Unable to load texture without filename or pre-defined id (filename definition for id %i not found)."), aId);
+ User::Leave(KErrNotFound);
+ }
+ }
+
+ // a guarantee that there's a filename available
+ HUI_ASSERT( fileName.Length()>0 );
+
+ // Reuse pre-existing entries:
+ // try first finding an entry based on id
+ if(entry == NULL && aId != 0)
+ {
+ TInt previouslyLoadedIndex = CheckTexture(aId);
+ if (previouslyLoadedIndex >= 0)
+ {
+ entry = iTextures[previouslyLoadedIndex];
+ }
+ }
+
+ // We are not allowed to change required texture id so we can't
+ // try again with the filename unless user does not care about id
+ if(aId == 0 && entry == NULL)
+ {
+ TInt previouslyLoadedIndex = CheckTexture(fileName, aFrameNumber);
+ if (previouslyLoadedIndex >= 0)
+ {
+ entry = iTextures[previouslyLoadedIndex];
+ }
+ }
+
+ // create new texture entry if there's not one
+ // available at this point
+ if(entry == NULL)
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::LoadTextureL() - Creating new texture."));
+
+ // in the case that a previously loaded slot was not found,
+ // create a new texture, which automatically registers a new
+ // texture entry in the iTextures list.
+ CHuiTexture::NewL();
+
+ // we assume that the newest entry was added the last
+ entry = iTextures[iTextures.Count()-1];
+
+ entry->iId = aId;
+ }
+ else
+ {
+ // We have a valid texture name and ID.
+ HUI_ASSERT(entry->iTexture);
+
+ // we have a pre-existing texture,
+ // but check that the texture is loaded ok, we can also
+ // return unloaded textures that are in the load queue
+ if (entry->iTexture->HasContent() || IsInLoadQueue(entry->iTexture))
+ {
+ // a previous texture exists!
+ HUI_ASSERT(entry->iTexture!=NULL);
+
+ HUI_DEBUG3(_L("CHuiTextureManager::LoadTextureL() - Reusing texture 0x%x (\"%S\", id: %i) No need to load."),
+ entry->iTexture, &entry->iTexture->ImageFileName(), entry->iId);
+ return *(entry->iTexture);
+ }
+ }
+
+ HUI_ASSERT(entry!=NULL);
+ HUI_ASSERT(entry->iTexture!=NULL);
+
+ // replace filename
+ // File names are relative to the image path.
+ entry->SetFileName(fileName);
+ entry->iTexture->SetImageFileNameL(fileName);
+ entry->iTexture->EnableShadow((aFlags & EHuiTextureUploadFlagGenerateShadow) != 0);
+ entry->iFrameNumber = aFrameNumber;
+
+ // add a content observer so that we can reload the texture
+ // during restoring
+ if (entry->iTexture->iContentObservers.Count()==0)
+ {
+ HUI_DEBUG2(_L("CHuiTextureManager::LoadTextureL() - Adding content observer 0x%x for texture 0x%x."), entry, entry->iTexture);
+ entry->iTexture->iContentObservers.AppendL(*entry);
+ }
+
+ HUI_DEBUG3(_L("CHuiTextureManager::LoadTextureL() - Enqueuing texture 0x%x (Name: \"%S\", Id: %i)."),
+ entry->iTexture, &entry->iTexture->ImageFileName(), entry->iId);
+
+ // Prepare for loading by creating a load queue entry.
+ SLoadQueueEntry loadqentry;
+ Mem::FillZ(&loadqentry, sizeof(loadqentry));
+ loadqentry.iLoading = entry;
+ entry->iMaxTextureSize = aTextureMaxSize;
+ entry->iFlags = aFlags;
+
+ // Textures are loaded one at a time, in the order they were requested.
+ User::LeaveIfError( iLoadQueue.Append(loadqentry) );
+
+ // Start loading images.
+ if(iState == EIdle)
+ {
+ StartLoading();
+
+ if(iState == ELoading)
+ {
+ // Notify observers that loading has started.
+ NotifyStateChange();
+ }
+ }
+
+ return *entry->iTexture;
+ }
+
+EXPORT_C CHuiTexture&
+CHuiTextureManager::CreateTextureL(TInt aId,
+ MHuiBitmapProvider* aBitmapProvider,
+ THuiTextureUploadFlags aFlags)
+ {
+ CHuiTexture* tex;
+
+ // can't create texture without id (or filename)
+ if (aId==0)
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::CreateTextureL() - ERROR! Can't create texture without valid id. Please use nonzero ids."));
+ User::Leave(KErrArgument);
+ }
+
+ // Provide an already created texture if such exists.
+ CHuiTexture* texture = NULL;
+ TRAPD(err, texture = TextureL(aId));
+ if(err == KErrNone)
+ {
+ ASSERT( texture );
+
+ // Update flags here because there is no other way to change flags.
+ CTextureEntry* entry = TextureEntry(CheckTexture(aId));
+ if (entry)
+ {
+ entry->iFlags = aFlags;
+ }
+
+ return *texture;
+ }
+
+ // Assert that the bitmap provider object exists.
+ HUI_ASSERT(aBitmapProvider != NULL);
+
+ HUI_DEBUG1(_L("CHuiTextureManager::CreateTextureL() - Requesting bitmap content from provider 0x%x .."), aBitmapProvider);
+
+ // Initialize bitmap and mask bitmap pointers to zero.
+ CFbsBitmap* bitmap = NULL;
+ CFbsBitmap* maskBitmap = NULL;
+
+ // Call the bitmapProvider method to load the bitmaps.
+ ASSERT( aBitmapProvider );
+ aBitmapProvider->ProvideBitmapL(aId, bitmap, maskBitmap);
+
+ // Error if main bitmap could not be loaded
+ User::LeaveIfNull(bitmap);
+ CleanupStack::PushL(bitmap);
+
+ UpdateFlags(*bitmap, maskBitmap, aFlags);
+
+ if (maskBitmap)
+ {
+ // A mask was provided, so pass this to texture creation.
+ CleanupStack::PushL(maskBitmap);
+ // create textures right away for these bitmaps
+ tex = &CreateTextureL(*bitmap, maskBitmap, aFlags, aId);
+ // get rid of bitmap and mask
+ CleanupStack::PopAndDestroy(maskBitmap);
+ }
+ else
+ {
+ // No mask, so create texture without one.
+ // create textures right away for these bitmaps
+ tex = &CreateTextureL(*bitmap, NULL, aFlags, aId);
+ }
+
+ CleanupStack::PopAndDestroy(bitmap);
+
+ // store the provider with the texture for Restore operations
+ HUI_ASSERT(CheckTexture(aId)>=0);
+ CTextureEntry * entry = TextureEntry(CheckTexture(aId));
+ entry->iBitmapProvider = aBitmapProvider;
+ entry->iFlags = aFlags;
+
+ HUI_ASSERT(entry->iTexture);
+
+ // add a content observer so that we can reload the texture
+ // during restoring
+ if (entry->iTexture->iContentObservers.Count()==0)
+ {
+ HUI_DEBUG2(_L("CHuiTextureManager::CreateTextureL() - Adding content observer 0x%x for texture 0x%x."), entry, entry->iTexture);
+ entry->iTexture->iContentObservers.AppendL(*entry);
+ }
+
+ return *tex;
+ }
+
+EXPORT_C CHuiTexture& CHuiTextureManager::CreateTextureL(CFbsBitmap& aBitmap,
+ const CFbsBitmap* aMask,
+ THuiTextureUploadFlags aFlags,
+ TInt aId)
+ {
+ TBool hasAlpha = (aMask != NULL);
+ TSize bitmapSize = aBitmap.SizeInPixels();
+
+ CHuiStatic::Tic(2);
+
+ // Verify that the bitmap size is same as the mask size.
+ if(hasAlpha && (bitmapSize != aMask->SizeInPixels()))
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::CreateTextureL() - Bitmap size is not compatible with the mask bitmap!"));
+ User::Leave(KErrArgument);
+ }
+
+ // Leave if the name and the id are empty.
+ if(aId==0)
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::CreateTextureL() - ERROR! Can't create texture without valid id or name."));
+ User::Leave(KErrArgument);
+ }
+
+ // If the texture has already been loaded, just return a reference.
+ TInt previouslyLoadedIndex = CheckTexture(aId);
+
+ if((previouslyLoadedIndex != -1) && IsLoaded(aId))
+ {
+ CHuiTexture * tex = iTextures[previouslyLoadedIndex]->iTexture;
+ HUI_ASSERT(tex);
+ HUI_DEBUG3(_L("CHuiTextureManager::CreateTextureL() - Reusing previously loaded texture (0x%x, \"%S\", id: %i)."),
+ tex, &tex->ImageFileName(), iTextures[previouslyLoadedIndex]->iId);
+ return *tex;
+ }
+
+ // create and append to the textures list (automatic)
+ CHuiTexture* texture = CHuiTexture::NewL();
+ // Set texture name
+ texture->SetImageFileNameL(_L(""));
+ // Set the texture id.
+ HUI_ASSERT(TextureEntryCount()>0);
+ CTextureEntry * te = TextureEntry(TextureEntryCount()-1);
+ te->iId = aId;
+
+ HUI_DEBUG3(_L("CHuiTextureManager::CreateTextureL() - Created new texture 0x%x (\"%S\", id: %i)."),
+ texture, &texture->ImageFileName(), aId);
+
+ // Let the texture know its size as soon as possible.
+ texture->SetSize(bitmapSize);
+
+ HUI_DEBUG6(_L("CHuiTextureManager::CreateTextureL() - Image for texture 0x%x is \"%S\": w=%i, h=%i, dm=%i, mdm=%i"),
+ texture,
+ &texture->ImageFileName(),
+ bitmapSize.iWidth,
+ bitmapSize.iHeight,
+ aBitmap.DisplayMode(),
+ (aMask != NULL ? aMask->DisplayMode() : ENone));
+
+ // Enable texture shadow.
+ texture->EnableShadow((aFlags & EHuiTextureUploadFlagGenerateShadow) != 0);
+
+ if (bitmapSize.iWidth != 0 && bitmapSize.iHeight != 0)
+ {
+ if (aFlags & EHuiTextureFlagAllowDirectBitmapUsage)
+ {
+ texture->UploadDirectL(aBitmap, aMask, aFlags);
+ }
+ else
+ {
+ texture->UploadL(aBitmap, aMask, aFlags);
+ }
+
+ }
+
+ HUI_DEBUG1(_L("CHuiTextureManager::CreateTextureL() - Upload for texture 0x%x done, notifying possible observers.."), texture);
+
+ // Store bits per pixel info to calculate texture memory usage
+ te->iBitDepth = TDisplayModeUtils::NumDisplayModeBitsPerPixel( aBitmap.DisplayMode() );
+ if( aMask )
+ {
+ te->iBitDepth = te->iBitDepth + TDisplayModeUtils::NumDisplayModeBitsPerPixel( aMask->DisplayMode() );
+ }
+
+ // Notify the observers
+ NotifyTextureLoaded(*texture, aId, KErrNone);
+
+ HUI_DEBUG2(_L("CHuiTextureManager::CreateTextureL() - Finished with texture 0x%x, toc: %f seconds"), texture, CHuiStatic::Toc(2));
+ return *texture;
+ }
+
+
+EXPORT_C void CHuiTextureManager::UpdateTextureFromBitmapL(TInt aId, MHuiBitmapProvider* aBitmapProvider)
+ {
+ TInt previouslyLoadedIndex = CheckTexture(aId);
+ if (previouslyLoadedIndex == KErrNotFound)
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ // Unload
+
+ UnloadTexture(aId);
+
+ // Upload with the new content
+
+ CTextureEntry* entry = iTextures[previouslyLoadedIndex];
+
+ HUI_DEBUG1(_L("CHuiTextureManager::UpdateTextureFromBitmapL() - Requesting bitmap content from provider 0x%x .."), aBitmapProvider);
+
+ // Initialize bitmap and mask bitmap pointers to zero.
+ CFbsBitmap* bitmap = NULL;
+ CFbsBitmap* maskBitmap = NULL;
+
+ // Call the bitmapProvider method to load the bitmaps.
+ if (!aBitmapProvider)
+ {
+ aBitmapProvider = entry->iBitmapProvider;
+ }
+ if (aBitmapProvider)
+ {
+ aBitmapProvider->ProvideBitmapL(aId, bitmap, maskBitmap);
+ }
+
+ // Error if main bitmap could not be loaded
+ if (!bitmap)
+ {
+ User::Leave(KErrNotFound);
+ }
+ CleanupStack::PushL(bitmap);
+
+ if (maskBitmap)
+ {
+ CleanupStack::PushL(maskBitmap);
+ }
+
+ TBool hasAlpha = (maskBitmap != NULL);
+ TSize bitmapSize = bitmap->SizeInPixels();
+
+ CHuiStatic::Tic(2);
+
+ // Verify that the bitmap size is same as the mask size.
+ if(hasAlpha && (bitmapSize != maskBitmap->SizeInPixels()))
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::UpdateTextureFromBitmapL() - Bitmap size is not compatible with the mask bitmap!"));
+ User::Leave(KErrArgument);
+ }
+
+ CHuiTexture* texture = entry->iTexture;
+ // Set texture name
+ texture->SetImageFileNameL(_L(""));
+
+ HUI_DEBUG6(_L("CHuiTextureManager::UpdateTextureFromBitmapL() - Image for texture 0x%x is \"%S\": w=%i, h=%i, dm=%i, mdm=%i"),
+ texture,
+ &texture->ImageFileName(),
+ bitmapSize.iWidth,
+ bitmapSize.iHeight,
+ bitmap->DisplayMode(),
+ (maskBitmap != NULL ? maskBitmap->DisplayMode() : ENone));
+
+ UpdateFlags(*bitmap, maskBitmap, entry->iFlags);
+
+ if (bitmapSize.iWidth != 0 && bitmapSize.iHeight != 0)
+ {
+ if (entry->iFlags & EHuiTextureFlagAllowDirectBitmapUsage)
+ {
+ texture->UploadDirectL(*bitmap, maskBitmap, entry->iFlags);
+ }
+ else
+ {
+ texture->UploadL(*bitmap, maskBitmap, entry->iFlags);
+ }
+ }
+ HUI_DEBUG2(_L("CHuiTextureManager::UpdateTextureFromBitmapL() - Finished with texture 0x%x, toc: %f seconds"), texture, CHuiStatic::Toc(2));
+
+ // Store bits per pixel info to calculate texture memory usage
+ entry->iBitDepth = TDisplayModeUtils::NumDisplayModeBitsPerPixel( bitmap->DisplayMode() );
+ if (maskBitmap)
+ {
+ entry->iBitDepth = entry->iBitDepth + TDisplayModeUtils::NumDisplayModeBitsPerPixel( maskBitmap->DisplayMode() );
+ }
+
+ if (maskBitmap)
+ {
+ CleanupStack::PopAndDestroy(maskBitmap);
+ }
+
+ CleanupStack::PopAndDestroy(bitmap);
+
+ // Store provider in case it has changed
+ if (aBitmapProvider)
+ {
+ entry->iBitmapProvider = aBitmapProvider;
+ }
+ }
+
+
+void CHuiTextureManager::UpdateFlags(const CFbsBitmap& aBitmap, const CFbsBitmap* aMaskBitmap,
+ THuiTextureUploadFlags& aFlags)
+ {
+ // Update EHuiTextureFlagUseBitmapDirectly flag if needed
+
+ if (aFlags & EHuiTextureFlagAllowDirectBitmapUsage)
+ {
+ TBool isDirectBitmapOk = !aBitmap.IsCompressedInRAM() &&
+ (!aMaskBitmap || !aMaskBitmap->IsCompressedInRAM());
+ // Check texture formats from the display
+ // Note: if there is no display the check cannot be done
+ if (isDirectBitmapOk)
+ {
+ isDirectBitmapOk = EFalse;
+ if (CHuiStatic::Env().DisplayCount() > 0)
+ {
+ RPointerArray<CHuiDisplay::CTextureBitmapFormat> formatArray;
+ TInt err = CHuiStatic::Env().PrimaryDisplay().GetPreferredTextureFormats(formatArray);
+ if (!err)
+ {
+ for (TInt i = 0; i < formatArray.Count(); i++)
+ {
+ if ((aBitmap.DisplayMode() == formatArray[i]->iImage) &&
+ ((!aMaskBitmap) || (aMaskBitmap->DisplayMode() == formatArray[i]->iMask)))
+ {
+ isDirectBitmapOk = ETrue;
+ }
+ }
+ }
+ formatArray.ResetAndDestroy();
+ }
+ }
+ // Update
+ if (!isDirectBitmapOk)
+ {
+ aFlags = (THuiTextureUploadFlags)(aFlags & ~EHuiTextureFlagAllowDirectBitmapUsage);
+ }
+ }
+ }
+
+
+RFs& CHuiTextureManager::FsSession() const
+ {
+ return iFS;
+ }
+
+
+EXPORT_C void CHuiTextureManager::PrependImagePath(TDes& aFileName) const
+ {
+ TFileName buf;
+
+ //allow app to load textures from different drive with complete path
+ TParse p1;
+ p1.Set(aFileName,0,0);
+
+ if (p1.DrivePresent())
+ {
+ return;
+ }
+
+ if(aFileName.Find(*iImagePath) == KErrNotFound)
+ {
+ buf = *iImagePath;
+ buf.Append(aFileName);
+ aFileName = buf;
+ }
+ }
+
+
+EXPORT_C void CHuiTextureManager::UnloadTexture(const TDesC& aImageName, const TInt aFrameNumber)
+ {
+ TFileName fileName = aImageName;
+ PrependImagePath(fileName);
+ TInt index = CheckTexture(fileName, aFrameNumber);
+ if (index >= 0)
+ {
+ HUI_DEBUG2(_L("CHuiTextureManager::UnloadTexture() - Unloading texture 0x%x (id: %i)."),
+ iTextures[index]->iTexture,
+ iTextures[index]->iId);
+ DoUnload(index);
+ return;
+ }
+ HUI_DEBUG1(_L("CHuiTextureManager::UnloadTexture() - Warning! Unable to unload \"%S\" - No such texture(s) found. Already unloaded?"), &fileName);
+ }
+
+
+EXPORT_C void CHuiTextureManager::UnloadTexture(TInt aId)
+ {
+ TInt index = CheckTexture(aId);
+ if (index >= 0)
+ {
+ HUI_DEBUG2(_L("CHuiTextureManager::UnloadTexture() - Unloading texture 0x%x (id: %i)."),
+ iTextures[index]->iTexture,
+ iTextures[index]->iId);
+ DoUnload(index);
+ return;
+ }
+ HUI_DEBUG1(_L("CHuiTextureManager::UnloadTexture() - Warning! Unable to unload id %i. No texture with such id. Already unloaded?"), aId);
+ }
+
+
+EXPORT_C void CHuiTextureManager::DefineFileNameL(TInt aId,
+ const TDesC& aImageName)
+ {
+ if (aId==0)
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::DefineFileNameL() - ERROR! Defining filename for texture id 0 is not allowed. Please use nonzero ids."));
+ User::Leave(KErrArgument); // can't specify filename for "no id"
+ }
+
+ // Look for an existing entry for the id.
+ for(TInt i = 0; i < iTextures.Count(); ++i)
+ {
+ if(iTextures[i]->iId == aId)
+ {
+ // Just set the new image name.
+ iTextures[i]->SetFileName(aImageName);
+ return;
+ }
+ }
+
+ // create a new texture, which automatically registers a new
+ // texture entry in the iTextures list.
+ CHuiTexture::NewL();
+ // we assume that the newest entry was added last
+ CTextureEntry* entry = iTextures[iTextures.Count()-1];
+ entry->iId = aId;
+ entry->SetFileName(aImageName);
+ }
+
+
+EXPORT_C TInt CHuiTextureManager::CheckTexture(const TDesC& aImageName, TInt aFrameNumber) const
+ {
+ if(aImageName.Length()==0)
+ {
+ // name empty, can't check
+ return -1;
+ }
+ for(TInt i = 0; i < iTextures.Count(); ++i)
+ {
+ CTextureEntry * te = iTextures[i];
+ // compare against texture manager entry filename (iFileName)
+ if((te->iFileName != NULL)
+ && (aImageName.Compare(*(te->iFileName)) == 0)
+ && te->iFrameNumber == aFrameNumber)
+ {
+ return i;
+ }
+
+ // compare against texture object imagefilename
+ if( te->iTexture
+ && te->iTexture->ImageFileName().Compare(aImageName) == 0
+ && te->iTexture->iFrameNumber == aFrameNumber)
+ {
+ return i;
+ }
+ }
+ // not found
+ return -1;
+ }
+
+
+EXPORT_C TInt CHuiTextureManager::CheckTexture(TInt aId) const
+ {
+ if(aId == 0)
+ {
+ // id not defined, can't search
+ return -1;
+ }
+ for(TInt i = 0; i < iTextures.Count(); ++i)
+ {
+ if(iTextures[i]->iId == aId)
+ {
+ return i;
+ }
+ }
+ // not found:
+ return -1;
+ }
+
+
+TBool CHuiTextureManager::IsInLoadQueue(const CHuiTexture * texture) const
+ {
+
+ if (texture == NULL)
+ {
+ return EFalse;
+ }
+
+ // textures in the load queue are not loaded yet,
+ // the others are assumed to be loaded..
+ for(TInt i = 0; i < iLoadQueue.Count(); ++i)
+ {
+ CTextureEntry* textureEntry = iLoadQueue[i].iLoading;
+ if(textureEntry->iTexture == texture)
+ {
+ // Still in the queue.
+ return ETrue;
+ }
+ }
+ return EFalse;
+ }
+
+TBool CHuiTextureManager::IsInLoadQueue(TInt id) const
+ {
+ // textures in the load queue are not loaded yet,
+ // the others are assumed to be loaded..
+ for(TInt i = 0; i < iLoadQueue.Count(); ++i)
+ {
+ if(iLoadQueue[i].iLoading->iId == id)
+ {
+ // Still in the queue.
+ return ETrue;
+ }
+ }
+ return EFalse;
+ }
+
+
+void CHuiTextureManager::StartLoading()
+ {
+ // Start the texture load active object if we're not loading
+ if(iState == EIdle)
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::StartLoading() - Starting load queue."));
+
+ // loop that finds next entry to load
+ while (1)
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::StartLoading() - Find next to be loaded."));
+
+ // try to schedule next image for loading..
+ TRAPD(err, DoLoadNextL());
+ // ok?
+
+ if(err != KErrNone)
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::StartLoading() - Found an error."));
+
+ HUI_ASSERT(iLoadQueue.Count()>0);
+ // remove the entry from the queue
+ SLoadQueueEntry entry = PopLoadedQueueEntry();
+ switch (err)
+ {
+ case KErrNoMemory:
+ {
+ HUI_DEBUG3( _L("CHuiTextureManager::StartLoading() - Unable to start loading \"%S\" (id %i): Out of memory. Trying to continue with %i items in the queue.."), &(entry.iLoading->iTexture->ImageFileName()), entry.iLoading->iId, iLoadQueue.Count());
+ break;
+ }
+ default:
+ {
+ HUI_DEBUG4( _L("CHuiTextureManager::StartLoading() - Unable to start loading \"%S\" (id %i): Leave error code %i. Trying to continue with %i items in the queue.."), &(entry.iLoading->iTexture->ImageFileName()), entry.iLoading->iId, err, iLoadQueue.Count());
+ break;
+ }
+ }
+ // Notify observers about the image loading error
+ NotifyTextureLoaded(*entry.iLoading->iTexture, entry.iLoading->iId, err);
+ // Image loading has been completed.
+ iState = EIdle;
+ continue;
+ }
+ else
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::StartLoading() - Found next texture to load."));
+ if(iLoadQueue.Count() == 0 && iLoadQueueHadValidTexture)
+ {
+ // During the load loop that has passed we have succesfully started to load
+ // at least one texture. So the state has been changed to ELoading, thus
+ // it is now changed back to EIdle.
+ NotifyStateChange();
+ iLoadQueueHadValidTexture = EFalse;
+ }
+ }
+
+ // leave the loop if we had no trouble scheduling the next
+ // image decode
+ break;
+ }
+
+ HUI_DEBUG(_L("CHuiTextureManager::StartLoading() - Load queue started."));
+ }
+ }
+
+
+CHuiTextureManager::SLoadQueueEntry CHuiTextureManager::PopLoadedQueueEntry()
+ {
+ SLoadQueueEntry entry = iLoadQueue[0];
+ HUI_DEBUG2( _L("CHuiTextureManager::PopLoadedQueueEntry() - Cleaning up load queue entry for \"%S\" (id %i)."),
+ &(entry.iLoading->iTexture->ImageFileName()), entry.iLoading->iId);
+ iLoadQueue.Remove(0);
+ // Delete the decoder.
+ delete entry.iDecoder;
+ entry.iDecoder = 0;
+ return entry;
+ }
+
+
+void CHuiTextureManager::DoLoadNextL()
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::DoLoadNextL() - Going into assert."));
+ __ASSERT_ALWAYS(iState == EIdle, THuiPanic::Panic(THuiPanic::EInternal));
+ HUI_DEBUG(_L("CHuiTextureManager::DoLoadNextL() - Survived assert."));
+
+ // Any loading tasks left?
+ if(iLoadQueue.Count() == 0)
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::DoLoadNextL() - No more items to load. Changing state to idle."));
+ return; // nothing else to be loaded.
+ }
+
+ // Start timing
+ CHuiStatic::Tic(2);
+
+ // Manager is now busy.
+ iState = ELoading;
+
+ HUI_DEBUG(_L("CHuiTextureManager::DoLoadNextL() - Fetching next load queue entry."));
+
+ // Fetch a load queue entry
+ SLoadQueueEntry& entry = iLoadQueue[0];
+ CHuiTexture* texture = entry.iLoading->iTexture;
+ HUI_ASSERT(texture != NULL);
+ HUI_DEBUG1(_L("CHuiTextureManager::DoLoadNext() - Starting to decode %S"), &texture->ImageFileName());
+
+ // Create a new image decoder for loading the image.
+ TFileName imageFileName = texture->ImageFileName(); // does not include image path
+ PrependImagePath(imageFileName);
+
+ delete entry.iDecoder;
+ entry.iDecoder = NULL;
+
+ TRAPD( err, entry.iDecoder = CImageDecoder::FileNewL(FsSession(), imageFileName, CImageDecoder::EOptionAlwaysThread) );
+
+ // check for errors..
+ if(err != KErrNone)
+ {
+ // Try to cancel the decoding (if possible)
+ if(entry.iDecoder)
+ {
+ entry.iDecoder->Cancel();
+ }
+ switch (err)
+ {
+ case KEComErrNoInterfaceIdentified:
+ {
+ HUI_DEBUG1( _L("CHuiTextureManager::DoLoadNext() - CImageDecoder failed to decode \"%S\". No plugin decoders were found."), &texture->ImageFileName() );
+ User::Leave(err); // re-leave with the error
+ }
+ case KErrPathNotFound:
+ {
+ HUI_DEBUG1( _L("CHuiTextureManager::DoLoadNext() - CImageDecoder failed to decode \"%S\". Path not found."), &texture->ImageFileName() );
+ User::Leave(err); // re-leave with the error
+ }
+ case KErrAccessDenied:
+ case KErrPermissionDenied:
+ {
+ HUI_DEBUG1( _L("CHuiTextureManager::DoLoadNext() - CImageDecoder failed to decode \"%S\". Access denied."), &texture->ImageFileName() );
+ User::Leave(err); // re-leave with the error
+ }
+ case KErrNotFound:
+ {
+ HUI_DEBUG1( _L("CHuiTextureManager::DoLoadNext() - CImageDecoder failed to decode \"%S\". Resource not found."), &texture->ImageFileName() );
+ User::Leave(err); // re-leave with the error
+ }
+ case KErrUnderflow:
+ {
+ HUI_DEBUG1( _L("CHuiTextureManager::DoLoadNext() - CImageDecoder failed to decode \"%S\". Not enough data in file to identify which plugin decoder to use."), &texture->ImageFileName() );
+ User::Leave(err); // re-leave with the error
+ }
+ case KErrNotSupported:
+ {
+ HUI_DEBUG1( _L("CHuiTextureManager::DoLoadNext() - CImageDecoder failed to decode \"%S\". Format not supported."), &texture->ImageFileName() );
+ User::Leave(err); // re-leave with the error
+ }
+ default:
+ {
+ HUI_DEBUG2( _L("CHuiTextureManager::DoLoadNext() - CImageDecoder failed to decode \"%S\". Unknown error (code %i)."), &texture->ImageFileName(), err );
+ User::Leave(err); // re-leave with the error
+ }
+ }
+ }
+
+ entry.iDecoder->SetDecoderThreadPriority(EPriorityAbsoluteBackgroundNormal);
+
+ // There is a valid texture in the load queue that we now start to load.
+ iLoadQueueHadValidTexture = ETrue;
+
+ // from decoder's frame info retrieve the framesize
+ const TInt frameCount = entry.iDecoder->FrameCount();
+ entry.iLoading->iFrameCount = frameCount;
+ if (frameCount && entry.iLoading->iFrameNumber>frameCount)
+ {
+ entry.iLoading->iFrameNumber = frameCount-1;
+ }
+
+ CHuiTextureAnimationState* textureAnimationState = NULL;
+
+ TInt groupId = 0;
+ TBool foundGroup = FindGroupIdByTextureId( entry.iLoading->iId, groupId );
+
+ if ( frameCount > 1 && NeedsAnimationState( *entry.iDecoder ) )
+ {
+ // It's animated texture which needs to be produced sequentially.
+ if ( !foundGroup )
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::DoLoadNextL() - Animation: Group not found."));
+
+ if ( iAnimationWithoutGroup &&
+ iAnimationWithoutGroup->CheckIfCanProduce(
+ imageFileName,
+ entry.iLoading->iFrameNumber,
+ frameCount ) )
+ {
+ // use iAnimationWithoutGroup
+ }
+ else
+ {
+ delete iAnimationWithoutGroup;
+ iAnimationWithoutGroup = NULL;
+
+ iAnimationWithoutGroup =
+ CHuiTextureAnimationState::NewL(
+ 0, imageFileName, frameCount );
+ }
+ textureAnimationState = iAnimationWithoutGroup;
+ }
+ else
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::DoLoadNextL() - Animation: Group found."));
+ textureAnimationState = CreateAnimationStateL(
+ groupId, imageFileName,
+ entry.iLoading->iFrameNumber, frameCount );
+ }
+ }
+ else
+ {
+ // No need to produce sequentially.
+ if ( foundGroup )
+ {
+ RemoveAnimationState( FindAnimationState( groupId ) );
+ }
+ }
+
+ if ( textureAnimationState != iAnimationWithoutGroup )
+ {
+ delete iAnimationWithoutGroup;
+ iAnimationWithoutGroup = NULL;
+ }
+
+ const TInt frameToBeLoaded =
+ !textureAnimationState ?
+ entry.iLoading->iFrameNumber :
+ textureAnimationState->GetNextFrameNumber();
+
+ TFrameInfo frameInfo(entry.iDecoder->FrameInfo(frameToBeLoaded));
+ entry.iLoading->iFrameInterval = frameInfo.iDelay.Int64();
+
+ if ( textureAnimationState )
+ {
+ textureAnimationState->OfferNextFrameInfo( frameInfo );
+ }
+
+ // check for alpha channel
+ // Gifs don't have alpha but support tranparency so the alpha flag is ignored currently
+ if(frameInfo.iFlags & TFrameInfo::ETransparencyPossible/* &&
+ frameInfo.iFlags & TFrameInfo::EAlphaChannel*/)
+ {
+ entry.iHasAlpha = ETrue;
+ }
+ else
+ {
+ entry.iHasAlpha = EFalse;
+ }
+
+ // Get the image original size
+ TRect bitmapSize = frameInfo.iFrameCoordsInPixels;
+ TSize overallSize =
+ !textureAnimationState ?
+ bitmapSize.Size() :
+ textureAnimationState->OverallSize();
+
+ entry.iOriginalSize = overallSize;
+
+ HUI_DEBUG6(_L("CHuiTextureManager::DoLoadNext() - (sub)Image %S (id %i): w=%i, h=%i, bpp=%i, dm=%i"),
+ &texture->ImageFileName(),
+ entry.iLoading->iId,
+ bitmapSize.Size().iWidth,
+ bitmapSize.Size().iHeight,
+ frameInfo.iBitsPerPixel,
+ frameInfo.iFrameDisplayMode);
+
+ HUI_DEBUG(_L("CHuiTextureManager::DoLoadNext() - Setting logical size of the bitmap."));
+
+ // Try to assign the original size to the image
+ texture->SetSize(overallSize);
+
+ // target resolution for texture, initially equal to bitmap size
+ TInt widthResolutionTarget = overallSize.iWidth;
+ TInt heightResolutionTarget = overallSize.iHeight;
+
+ TSize maxTexSize = entry.iLoading->iMaxTextureSize;
+
+ // Assign new texture resolution target dimensions
+ // if we have explicitly requested them
+ if( (entry.iLoading->iFlags & EHuiTextureUploadFlagDoNotRetainResolution)
+ && maxTexSize.iWidth > 0
+ && maxTexSize.iHeight > 0)
+ {
+ HUI_DEBUG3(_L("CHuiTextureManager::DoLoadNext() - Custom texture size for image %S: w=%i, h=%i"),
+ &texture->ImageFileName(),
+ maxTexSize.iWidth,
+ maxTexSize.iHeight);
+
+ // assign new target resolution for decoder-based scaling
+ if(maxTexSize.iWidth < widthResolutionTarget)
+ {
+ widthResolutionTarget = maxTexSize.iWidth;
+ }
+ if(maxTexSize.iHeight < heightResolutionTarget)
+ {
+ heightResolutionTarget = maxTexSize.iHeight;
+ }
+ }
+
+ // Set up segmentation so we know what kind of texture (and texture
+ // size) we are dealing with
+ texture->SetupSegmentsL(overallSize,
+ TSize(widthResolutionTarget, heightResolutionTarget),
+ entry.iLoading->iFlags);
+
+ // we can do direct decoder-based scaling,
+ // if only a single segment texture is used
+ if( !textureAnimationState &&
+ texture->SegmentCount() == 1 &&
+ (texture->SegmentTextureSize(0).iWidth < bitmapSize.Size().iWidth ||
+ texture->SegmentTextureSize(0).iHeight < bitmapSize.Size().iHeight))
+ {
+
+ // assign new texture size target dimensions from the calculated segment 0
+ widthResolutionTarget = texture->SegmentTextureSize(0).iWidth;
+ heightResolutionTarget = texture->SegmentTextureSize(0).iHeight;
+
+ // we need to do some downscaling, but can we do arbitrary
+ // scaling as well?
+ if(frameInfo.iFlags & TFrameInfo::EFullyScaleable)
+ {
+ // .. yes, arbitrary scaling is possible
+ // just assign the new size to the bitmap
+ // so that it will be scaled accordingly during
+ // conversion
+ HUI_DEBUG3(_L("CHuiTextureManager::DoLoadNext() - Downscaling image %S to size %ix%i."),
+ &texture->ImageFileName(),
+ widthResolutionTarget,
+ heightResolutionTarget);
+ }
+ else
+ {
+ // all decoders should be able to do 1/2, 1/4, 1/8 DCT Scaling
+ // calculate nearest half size for the decoder-downscaled bitmap
+ // halve image width&height to size which is closest larger match
+ // of the bitmap size
+ TInt halvedWidth = bitmapSize.Size().iWidth;
+ TInt halvedHeight = bitmapSize.Size().iHeight;
+ TInt halveFactor = 1; // this limits the halving to 1/8 max
+ while ( ((halvedWidth >> 1) > widthResolutionTarget) &&
+ ((halvedHeight >> 1) > heightResolutionTarget)
+ && (halveFactor << 1) <= 8)
+ {
+ halveFactor <<= 1;
+ }
+ halvedWidth = halvedWidth / halveFactor;
+ halvedHeight = halvedHeight / halveFactor;
+ // .. the bitmap will be downscaled further to the correct
+ // dimensions by ImageLoadingCompleteL after the bitmap has been decoded
+ HUI_DEBUG4(_L("CHuiTextureManager::DoLoadNext() - Halving image %S size to %ix%i (factor %i)."),
+ &texture->ImageFileName(),
+ halvedWidth,
+ halvedHeight, halveFactor);
+ widthResolutionTarget = halvedWidth;
+ heightResolutionTarget = halvedHeight;
+ }
+ }
+ else
+ {
+ // either multi-segmented or no need for scaling..
+ HUI_DEBUG(_L("CHuiTextureManager::DoLoadNext() - Decoder-based downscaling not required/possible."));
+ }
+
+ if ( textureAnimationState )
+ {
+ // we convert subframe completely
+ widthResolutionTarget = bitmapSize.Size().iWidth;
+ heightResolutionTarget = bitmapSize.Size().iHeight;
+ }
+
+ if (!(entry.iLoading->iFlags & EHuiTextureUploadFlagRetainColorDepth) && iBitmap->DisplayMode()!=EColor64K)
+ {
+ // (Re)Create the bitmap in EColor64K (16bit) mode to save memory
+ iBitmap->Create(TSize(widthResolutionTarget, heightResolutionTarget), EColor64K);
+ }
+ else if ((entry.iLoading->iFlags & EHuiTextureUploadFlagRetainColorDepth) && iBitmap->DisplayMode()==EColor64K)
+ {
+ // (Re)Create the bitmap in EColor16MU (24bit) mode retain the color information
+ iBitmap->Create(TSize(widthResolutionTarget, heightResolutionTarget), EColor16MU);
+ }
+ else
+ {
+ // no need to recreate the bitmap, but assign the new size!
+ iBitmap->Resize(TSize(widthResolutionTarget, heightResolutionTarget));
+ }
+
+ if (iBitmap->DisplayMode()==EColor64K)
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::DoLoadNext() - Decoding to 16bit image to conserve memory."));
+ }
+ // Decode ( and rescale ) to bitmap.
+ if(entry.iHasAlpha)
+ {
+ // set the alpha channel bitmap to the same size than the color bitmap
+ iMaskBitmap->Resize(TSize(widthResolutionTarget, heightResolutionTarget));
+ entry.iDecoder->Convert(&iStatus, *iBitmap, *iMaskBitmap, frameToBeLoaded);
+ }
+ else
+ {
+ // Save some memory by making the unused alpha channel bitmap
+ // very small.
+ iMaskBitmap->Resize(TSize(4, 4));
+ entry.iDecoder->Convert(&iStatus, *iBitmap, frameToBeLoaded);
+ }
+
+ // Wait for completion.
+ SetActive();
+
+ HUI_DEBUG1(_L("CHuiTextureManager::DoLoadNext() - Exiting, toc %.2f sec"), CHuiStatic::Toc(2));
+ }
+
+CHuiTextureAnimationState* CHuiTextureManager::CreateAnimationStateL(
+ TInt aGroupId, const TDesC& aImageFile,
+ TInt aFrameNumber, TInt aFrameCount )
+ {
+ CHuiTextureAnimationState* result = FindAnimationState( aGroupId );
+
+ TBool recreate = !result || !aFrameNumber;
+ if ( !recreate )
+ {
+ // result != NULL => check if result is animation state of some
+ // previous frame
+ recreate =
+ !result->CheckIfCanProduce( aImageFile, aFrameNumber, aFrameCount );
+ }
+
+ if ( recreate )
+ {
+ // First frame, let's just recreate animation state.
+ RemoveAnimationState( result );
+ result = NULL;
+
+ result = CHuiTextureAnimationState::NewL(
+ aGroupId, aImageFile, aFrameCount );
+ CleanupStack::PushL( result );
+ iAnimations.AppendL( result );
+ CleanupStack::Pop( result );
+ }
+
+ return result;
+ }
+
+CHuiTextureAnimationState* CHuiTextureManager::FindAnimationState(
+ TInt aGroupId )
+ {
+ CHuiTextureAnimationState* result = NULL;
+ const TInt count = iAnimations.Count();
+ for ( TInt i = 0; i < count; i++ )
+ {
+ CHuiTextureAnimationState* state = iAnimations[ i ];
+ if ( state->OwnerTextureGroupId() == aGroupId )
+ {
+ result = state;
+ break;
+ }
+ }
+ return result;
+ }
+
+void CHuiTextureManager::RemoveAnimationState(
+ CHuiTextureAnimationState* aState )
+ {
+ if ( aState )
+ {
+ TInt pos = iAnimations.Find( aState );
+ if ( pos != KErrNotFound )
+ {
+ iAnimations.Remove( pos );
+ }
+ delete aState;
+ }
+ }
+
+TBool CHuiTextureManager::FindGroupIdByTextureId(
+ TInt aTextureId, TInt& aGroupId ) const
+ {
+ TBool found = EFalse;
+ const TInt count = iAnimatedTextureGroupItems.Count();
+ TInt i = 0;
+ while ( !found && ( i < count ) )
+ {
+ const TAnimatedTextureGroupItem& item = iAnimatedTextureGroupItems[ i ];
+ if ( item.iTextureId == aTextureId )
+ {
+ found = ETrue;
+ aGroupId = item.iGroupId;
+ }
+ i++;
+ }
+ return found;
+ }
+
+TBool CHuiTextureManager::NeedsAnimationState( const CImageDecoder& aDecoder )
+ {
+ // If this image contains any special image disposal methods, then
+ // use animation state.
+
+ const TInt frames = aDecoder.FrameCount();
+ TBool result = EFalse;
+
+ for ( TInt i = 0; !result && i < frames; ++i )
+ {
+ const TFrameInfo& info = aDecoder.FrameInfo( i );
+ const TUint32 disposalFlags =
+ info.iFlags &
+ ( TFrameInfo::ELeaveInPlace |
+ TFrameInfo::ERestoreToBackground |
+ TFrameInfo::ERestoreToPrevious );
+
+ result = result || disposalFlags;
+ }
+
+ return result;
+ }
+
+void CHuiTextureManager::DoUnload(TInt index)
+ {
+ HUI_ASSERT(index>=0 && index < iTextures.Count());
+ CHuiTexture * t = iTextures[index]->iTexture;
+ if (t == NULL)
+ {
+ HUI_DEBUG1(_L("CHuiTextureManager::UnloadTexture() - Not unloading a NULL texture at index %i."), index);
+ return;
+ }
+
+ HUI_DEBUG3(_L("CHuiTextureManager::UnloadTexture() - Unloading texture \"%S\" id %i at index %i."), &t->ImageFileName(), iTextures[index]->iId, index);
+ // Is this in the queue?
+ if(IsInLoadQueue(t))
+ {
+ // Not loaded yet, can't unload. Mark it as unloaded, though,
+ // so it will be discarded when the loading completes.
+ for(TInt i = 0; i < iLoadQueue.Count(); ++i)
+ {
+ if(iLoadQueue[i].iLoading->iTexture == t)
+ {
+ HUI_DEBUG1(_L("CHuiTextureManager::UnloadTexture() - Marking \"%S\" as unloaded (still in the load queue). "), &t->ImageFileName());
+ iLoadQueue[i].iUnloaded = ETrue;
+ return;
+ }
+ }
+ }
+
+ // Just delete the contents of the texture
+ t->Reset();
+ HUI_ASSERT(!t->HasContent());
+ }
+
+
+EXPORT_C TInt CHuiTextureManager::RunError( TInt /*aError*/ )
+ {
+ // Should never be called, RunL is responsible for handling all error cases
+ HUI_ASSERT(EFalse);
+ return KErrNone;
+ }
+
+
+EXPORT_C void CHuiTextureManager::RunL()
+ {
+ if( iReleaseState == EReleased ||
+ iReleaseState == EPartiallyReleased ||
+ iReleaseState == EReleasing )
+ {
+ // Set the loading state to idle, but do not notify observers of this,
+ // since we are released.
+ // This has to be done so that unfinished loading can be restarted in
+ // the RestoreL().
+ iState = EIdle;
+ // Leave the texture to the load queue and load it again after restore.
+ return;
+ }
+
+ TInt status = iStatus.Int();
+
+ if ( status == KErrNone )
+ {
+ status = ImageLoadingContinue();
+ if ( status > KErrNone )
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::RunL() - Animation: Continue loading."));
+ return;
+ }
+ }
+
+ // remove the loaded entry from the queue
+ SLoadQueueEntry entry = PopLoadedQueueEntry();
+
+ // Image loading has been completed.
+ iState = EIdle;
+
+ // check status
+ if( status == KErrNone )
+ {
+ // ok, we have a loaded image, but
+ // we still need to do texture uploads
+ // and possibly some image conversions
+ TRAPD( err, ImageLoadingCompleteL(entry) );
+
+ if(err != KErrNone)
+ {
+ delete iAnimationWithoutGroup;
+ iAnimationWithoutGroup = NULL;
+
+ switch (err)
+ {
+ case KErrNoMemory:
+ {
+ HUI_DEBUG3( _L("CHuiTextureManager::RunL() - ERROR! Failed to convert image to texture. Out of memory in ImageLoadingCompleteL(). Source image was \"%S\" (id %i). Trying to continue with %i items in the queue.."),
+ &(entry.iLoading->iTexture->ImageFileName()), entry.iLoading->iId, iLoadQueue.Count() );
+ break;
+ }
+ default:
+ {
+ HUI_DEBUG4( _L("CHuiTextureManager::RunL() - Error %i occurred during image upload/conversion to texture. Image filename was: \"%S\" (id %i). Trying to continue with %i items in the queue.."),
+ err, &(entry.iLoading->iTexture->ImageFileName()), entry.iLoading->iId, iLoadQueue.Count() );
+ break;
+ }
+ }
+ // Notify observers about the image upload error
+ NotifyTextureLoaded(*entry.iLoading->iTexture, entry.iLoading->iId, err);
+ }
+ }
+ else
+ {
+ HUI_DEBUG2( _L("CHuiTextureManager::RunL() - Image decoding error while decoding \"%S\" (id %i). Bypassing image.."), &(entry.iLoading->iTexture->ImageFileName()), entry.iLoading->iId);
+
+ delete iAnimationWithoutGroup;
+ iAnimationWithoutGroup = NULL;
+
+ // notify sb of failed image load!
+ NotifyTextureLoaded(*entry.iLoading->iTexture, entry.iLoading->iId, status);
+ }
+
+ // Continue loading entries.
+ StartLoading();
+
+ if(iLoadQueue.Count() == 0)
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::RunL() - No more images to load, exiting.."));
+ }
+ }
+
+
+EXPORT_C void CHuiTextureManager::DoCancel()
+ {
+ if(iLoadQueue.Count() > 0)
+ {
+ iLoadQueue[0].iDecoder->Cancel();
+ }
+
+ iState = EIdle;
+ }
+
+TInt CHuiTextureManager::ImageLoadingContinue()
+ {
+ TInt status = KErrNone;
+
+ const SLoadQueueEntry& entry = iLoadQueue[0];
+
+ TInt groupId = 0;
+ CHuiTextureAnimationState* state = NULL;
+ if ( iAnimationWithoutGroup )
+ {
+ state = iAnimationWithoutGroup;
+ }
+ else if ( FindGroupIdByTextureId( entry.iLoading->iId, groupId ) )
+ {
+ state = FindAnimationState( groupId );
+ }
+ else
+ {
+ // state = NULL;
+ }
+
+ if ( state &&
+ ( state->GetNextFrameNumber() != entry.iLoading->iFrameNumber ) )
+ {
+ // Someone has asked animated frames not in sequence -
+ // very inefficient!
+ HUI_DEBUG(_L("CHuiTextureManager::ImageLoadingContinue: Frames not requested in sequence."));
+ TRAP( status,
+ state->ProceedWithoutNextFrameL(
+ iBitmap,
+ entry.iHasAlpha ? iMaskBitmap : NULL ) );
+
+ if ( status == KErrNone )
+ {
+ // Image loading has been completed.
+ iState = EIdle;
+ StartLoading();
+ status = 1; // indicate that started loading.
+ }
+ }
+
+ return status;
+ }
+
+void CHuiTextureManager::ImageLoadingCompleteL(SLoadQueueEntry& aEntry)
+ {
+ CHuiTexture* tex = aEntry.iLoading->iTexture;
+ HUI_ASSERT(tex);
+ tex->iFrameNumber = aEntry.iLoading->iFrameNumber;
+ tex->iFrameCount = aEntry.iLoading->iFrameCount;
+ tex->iFrameInterval = aEntry.iLoading->iFrameInterval;
+
+ if(iReleaseState != ENormal)
+ {
+ HUI_DEBUG1(_L("CHuiTextureManager::ImageLoadingCompleteL() - Unable to upload bitmap data for \"%S\". Texture manager has been released."), &tex->ImageFileName());
+ return;
+ }
+
+ if ( tex->iFrameCount > 1 )
+ {
+ ProcessAnimatedFrameL( aEntry );
+ }
+ TBool hasAlpha = aEntry.iHasAlpha;
+
+ delete iAnimationWithoutGroup;
+ iAnimationWithoutGroup = NULL;
+
+ TSize* maxTexSize = &aEntry.iLoading->iMaxTextureSize;
+ if(((maxTexSize->iWidth != 0) && (maxTexSize->iHeight != 0)) && iBitmap->SizeInPixels() != aEntry.iLoading->iMaxTextureSize )
+ {
+ // The decoder failed to constrain the texture dimensions properly, due to its internal limitations.
+ // So we need to scale the texture(s) down further to the correct size.
+
+ CFbsBitmap* dest = new (ELeave) CFbsBitmap();
+ CleanupStack::PushL( dest );
+ User::LeaveIfError( dest->Create(*maxTexSize, iBitmap->DisplayMode()) );
+ HuiUtil::ScaleFbsBitmapL(*iBitmap, *dest);
+ CleanupStack::Pop( dest );
+ delete iBitmap;
+ iBitmap = dest;
+
+ if( hasAlpha )
+ {
+ // Scale the alpha as well.
+ dest = new (ELeave) CFbsBitmap();
+ CleanupStack::PushL( dest );
+ User::LeaveIfError(
+ dest->Create(*maxTexSize, iMaskBitmap->DisplayMode()) );
+ HuiUtil::ScaleFbsBitmapL(*iMaskBitmap, *dest);
+ CleanupStack::Pop( dest );
+ delete iMaskBitmap;
+ iMaskBitmap = dest;
+ }
+ }
+
+ HUI_DEBUG3(_L("CHuiTextureManager::ImageLoadingCompleteL() - Loading complete for \"%S\". Uploading %ix%i FBS bitmap to texture.."),
+ &tex->ImageFileName(),
+ iBitmap->SizeInPixels().iWidth,
+ iBitmap->SizeInPixels().iHeight);
+
+ // Upload without compression.
+ tex->UploadL(*iBitmap,
+ (hasAlpha? iMaskBitmap: NULL),
+ aEntry.iLoading->iFlags);
+
+ // Store bits per pixel info to calculate texture memory usage
+ aEntry.iLoading->iBitDepth = TDisplayModeUtils::NumDisplayModeBitsPerPixel( iBitmap->DisplayMode() );
+ if( iMaskBitmap )
+ {
+ aEntry.iLoading->iBitDepth = aEntry.iLoading->iBitDepth +
+ TDisplayModeUtils::NumDisplayModeBitsPerPixel( iMaskBitmap->DisplayMode() );
+ }
+
+ // Now we're setting up the real texture, no more placeholder needed
+ tex->SetPlaceholder(NULL);
+
+ HUI_DEBUG2(_L("CHuiTextureManager::ImageLoadingCompleteL() - ... Upload done. Setting original size of %ix%i pixels."),
+ aEntry.iOriginalSize.iWidth,
+ aEntry.iOriginalSize.iHeight);
+
+ // (Re)set the original size of the image as the logical size
+ tex->SetSize(aEntry.iOriginalSize);
+
+ // Notify the observers of loaded texture
+ NotifyTextureLoaded(*tex, aEntry.iLoading->iId, KErrNone);
+
+ // Unload, if the unloading was already requested while loading!
+ if(aEntry.iUnloaded)
+ {
+ UnloadTexture(tex->ImageFileName(),tex->iFrameNumber);
+ }
+
+ HUI_DEBUG(_L("CHuiTextureManager::ImageLoadingCompleteL() - Done. "));
+ }
+
+void CHuiTextureManager::ProcessAnimatedFrameL(SLoadQueueEntry& aEntry)
+ {
+ // Animated file - produce next frame.
+ CFbsBitmap* frameBitmap = NULL;
+ CFbsBitmap* frameMask = NULL;
+
+ // ImageFileName() does not include image path
+ CHuiTextureAnimationState* state = NULL;
+ TInt groupId = 0;
+ if ( iAnimationWithoutGroup )
+ {
+ state = iAnimationWithoutGroup;
+ }
+ else if ( FindGroupIdByTextureId( aEntry.iLoading->iId, groupId ) )
+ {
+ state = FindAnimationState( groupId );
+ }
+
+ if ( !state )
+ {
+ return;
+ }
+
+ HUI_DEBUG1(_L("CHuiTextureManager::ProcessAnimatedFrameL: Producing next frame (%d)."),
+ state->GetNextFrameNumber() );
+
+ state->ProduceNextFrameL(
+ frameBitmap, frameMask,
+ iBitmap, aEntry.iHasAlpha ? iMaskBitmap : NULL );
+
+ HUI_DEBUG2(_L("CHuiTextureManager::ProcessAnimatedFrameL: Next frame produced (%x, %x)."),
+ frameBitmap, frameMask );
+
+ aEntry.iHasAlpha = ( frameMask != NULL );
+ if ( frameBitmap != iBitmap )
+ {
+ delete iBitmap;
+ iBitmap = frameBitmap;
+ }
+
+ if ( frameMask && (frameMask != iMaskBitmap) )
+ {
+ delete iMaskBitmap;
+ iMaskBitmap = frameMask;
+ }
+ }
+
+EXPORT_C TInt CHuiTextureManager::LoadQueueCount() const
+ {
+ return iLoadQueue.Count();
+ }
+
+
+EXPORT_C void CHuiTextureManager::AdvanceTime(TReal32 aElapsedTime) const
+ {
+ for(TInt i = 0; i < iAnimatedTextures.Count(); ++i)
+ {
+ iAnimatedTextures[i].AdvanceTime(aElapsedTime);
+ }
+ NotifyTextureAutoSizeObservers();
+ // Write total memory consumed on rendering textures as an info message,
+ // if feature is enabled from central repository Rnd flag
+ if ( iEnableTexMemCalculation )
+ {
+ TextureMemUsage();
+ }
+ }
+
+
+EXPORT_C void CHuiTextureManager::SetProcessor(CHuiTextureProcessor* aProcessor)
+ {
+ // Since we have ownership of the processor, delete the previous one if
+ // there is one.
+ if(iProcessor)
+ {
+ delete iProcessor;
+ iProcessor = NULL;
+ }
+
+ iProcessor = aProcessor;
+ }
+
+
+EXPORT_C CHuiTextureProcessor& CHuiTextureManager::Processor()
+ {
+ if(!iProcessor)
+ {
+ THuiPanic::Panic(THuiPanic::ETextureManagerNoProcessor);
+ }
+ return *iProcessor;
+ }
+
+
+void CHuiTextureManager::CancelLoadingOfTexture(CHuiTexture& aTexture)
+ {
+ for(TInt i = 0; i < iLoadQueue.Count(); ++i)
+ {
+ if(iLoadQueue[i].iLoading->iTexture == &aTexture)
+ {
+ // Texture found from the load queue.
+ if(i == 0 && iState == ELoading)
+ {
+ // Texture is currently loading
+ Cancel();
+ PopLoadedQueueEntry();
+ StartLoading();
+ }
+ else
+ {
+ // Delete the decoder and remove entry.
+ delete iLoadQueue[i].iDecoder;
+ iLoadQueue.Remove(i);
+ }
+ break;
+ }
+ }
+ }
+
+
+void CHuiTextureManager::NotifyStateChange() const
+ {
+ for(TInt index = 0; index < iStateObservers.Count(); ++index)
+ {
+ iStateObservers[index].TextureManagerStateChanged(*this);
+ }
+ }
+
+
+EXPORT_C void CHuiTextureManager::NotifyTextureLoaded(CHuiTexture& aTexture,
+ TInt aTextureId,
+ TInt aErrorCode) const
+ {
+ aTexture.SetTextureChanged(ETrue);
+ for(TInt index = 0; index < iLoadObservers.Count(); ++index)
+ {
+ iLoadObservers[index].TextureLoadingCompleted(aTexture, aTextureId, aErrorCode);
+ }
+ }
+
+EXPORT_C CHuiTextureManager::CTextureEntry * CHuiTextureManager::TextureEntry(TInt aIndex)
+ {
+ // check limits
+ if ( aIndex < iTextures.Count() )
+ {
+ return iTextures[aIndex];
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+EXPORT_C TInt CHuiTextureManager::TextureEntryCount() const
+ {
+ return iTextures.Count();
+ }
+
+EXPORT_C TBool CHuiTextureManager::Release()
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::Release() - Called."));
+
+ HUI_ASSERT(iReleaseState == ENormal);
+ iReleaseState = EReleasing;
+
+ TBool allReleased = ETrue; // by default, all texures are released.
+
+ // Release all textures. Use an order inverse to creation order.
+ for(TInt i = iTextures.Count() - 1; i >= 0; --i)
+ {
+ CHuiTexture * tex = iTextures[i]->iTexture;
+ if (tex)
+ {
+ // This is called when application goes into the backgrounf
+ // If release priority is set to 0, the texture should not be released.
+ if ( tex->Priority() == 0 )
+ {
+ HUI_DEBUG5(_L("CHuiTextureManager::Release() - Not releasing priority texture 0x%x (\"%S\", id: %i) [%i/%i]"),
+ tex, &(tex->ImageFileName()), iTextures[i]->iId, i+1, iTextures.Count());
+ allReleased = EFalse;
+ }
+ else
+ {
+ HUI_DEBUG5(_L("CHuiTextureManager::Release() - Releasing texture 0x%x (\"%S\", id: %i) [%i/%i]"),
+ tex, &(tex->ImageFileName()), iTextures[i]->iId, i+1, iTextures.Count());
+ tex->Release();
+ }
+ }
+ else
+ {
+ HUI_DEBUG4(_L("CHuiTextureManager::Release() - Not releasing unloaded texture 0x%x, id: %i) [%i/%i]"),
+ tex, iTextures[i]->iId, i+1, iTextures.Count());
+ }
+ }
+
+ HUI_DEBUG(_L("CHuiTextureManager::Release() - Release processor."));
+
+ // Release texture processor.
+ if(iProcessor)
+ {
+ iProcessor->Release();
+ }
+
+ HUI_ASSERT(iReleaseState == EReleasing);
+ if ( allReleased )
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::Release() - Exiting (EReleased)."));
+ iReleaseState = EReleased;
+ }
+ else
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::Release() - Exiting (EPartiallyReleased)."));
+ iReleaseState = EPartiallyReleased;
+ }
+ return allReleased;
+ }
+
+
+EXPORT_C void CHuiTextureManager::RestoreL()
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::RestoreL() - Called."));
+
+ HUI_ASSERT(iReleaseState == EReleased || iReleaseState == EPartiallyReleased );
+ iReleaseState = ERestoring;
+
+ // Restore texture processor.
+ if(iProcessor)
+ {
+ iProcessor->RestoreL();
+ }
+
+ // Restore all textures. Use same order as in which the textures were created.
+ for(TInt i = 0; i < iTextures.Count(); ++i)
+ {
+ CHuiTexture * tex = iTextures[i]->iTexture;
+ if (tex)
+ {
+ if ( tex->HasContent() )
+ {
+ HUI_DEBUG5(_L("CHuiTextureManager::RestoreL() - Alredy has content texture 0x%x (\"%S\", id: %i) [%i/%i]"),
+ tex, &(tex->ImageFileName()), iTextures[i]->iId, i+1, iTextures.Count());
+ }
+ else
+ {
+ HUI_DEBUG5(_L("CHuiTextureManager::RestoreL() - Restoring texture 0x%x (\"%S\", id: %i) [%i/%i]"),
+ tex, &(tex->ImageFileName()), iTextures[i]->iId, i+1, iTextures.Count());
+ // Restore the texture.
+ tex->RestoreL();
+ }
+ }
+ else
+ {
+ HUI_DEBUG4(_L("CHuiTextureManager::RestoreL() - Not restoring unloaded texture 0x%x, id: %i) [%i/%i]"),
+ tex, iTextures[i]->iId, i+1, iTextures.Count());
+ }
+ }
+
+ // Restart loading of textures that still might be in the load queue.
+ StartLoading();
+
+ HUI_ASSERT(iReleaseState == ERestoring);
+ iReleaseState = ENormal;
+ }
+
+EXPORT_C void CHuiTextureManager::NotifySkinChangedL()
+ {
+ for(TInt i = iTextures.Count()-1; i >= 0; i--)
+ {
+ CHuiTexture * tex = iTextures[i]->iTexture;
+ if (tex &&
+ tex->HasContent() &&
+ tex->IsSkinContent())
+ {
+ tex->Release();
+ tex->RestoreL();
+ }
+ }
+ }
+
+EXPORT_C TInt CHuiTextureManager::AddAnimatedTextureGroupL(
+ const RArray<TInt>& aTextureIds )
+ {
+ const TInt count = aTextureIds.Count();
+
+ // Zero ids are not allowed here
+ for ( TInt j = 0; j < count; j++ )
+ {
+ if ( !aTextureIds[ j ] )
+ {
+ User::Leave( KErrNotSupported );
+ }
+ }
+
+ TInt result = 0;
+ if ( count )
+ {
+ result = aTextureIds[ 0 ];
+
+ // Reserve space so next loop cannot fail.
+ iAnimatedTextureGroupItems.ReserveL(
+ iAnimatedTextureGroupItems.Count() + aTextureIds.Count() );
+
+ TAnimatedTextureGroupItem item;
+ item.iGroupId = result;
+
+ for ( TInt i = 0; i < count; i++ )
+ {
+ item.iTextureId = aTextureIds[ i ];
+
+ (void)iAnimatedTextureGroupItems.
+ Append( item ); // ought not to fail due to Reserve.
+ }
+ }
+
+ return result;
+ }
+
+EXPORT_C void CHuiTextureManager::RemoveAnimatedTextureGroup( TInt aGroupId )
+ {
+ // Remove animated texture group items.
+ const TInt count = iAnimatedTextureGroupItems.Count();
+ for ( TInt i = count - 1; i >= 0; --i )
+ {
+ if ( iAnimatedTextureGroupItems[ i ].iGroupId == aGroupId )
+ {
+ iAnimatedTextureGroupItems.Remove( i );
+ }
+ }
+
+ RemoveAnimationState( FindAnimationState( aGroupId ) );
+ }
+
+// CHuiTextureManager::CTextureEntry
+
+CHuiTextureManager::CTextureEntry::CTextureEntry(
+ TInt aId,
+ const TFileName & aFileName,
+ const TSize& aMaxTextureSize,
+ THuiTextureUploadFlags aFlags,
+ TInt aFrameNumber )
+ : iId(aId), iFileName(NULL),
+ iTexture(NULL),
+ iMaxTextureSize(aMaxTextureSize), iFlags(aFlags),
+ iBitmapProvider(NULL),
+ iFrameNumber(aFrameNumber),
+ iFrameCount(0),
+ iFrameInterval(0)
+ {
+ SetFileName(aFileName);
+ }
+
+CHuiTextureManager::CTextureEntry::CTextureEntry(TInt aId, CHuiTexture * aTexture)
+ : iId(aId),
+ iFileName(NULL),
+ iTexture(aTexture),
+ iMaxTextureSize(TSize(0,0)),
+ iFlags(EHuiTextureUploadFlagDefault),
+ iBitmapProvider(NULL),
+ iFrameNumber(0),
+ iFrameCount(0),
+ iFrameInterval(0)
+ {
+ }
+
+CHuiTextureManager::CTextureEntry::CTextureEntry(const CTextureEntry &aSrc)
+ : iId(aSrc.iId),
+ iFileName(NULL),
+ iTexture(aSrc.iTexture),
+ iMaxTextureSize(aSrc.iMaxTextureSize),
+ iFlags(aSrc.iFlags),
+ iBitmapProvider(NULL),
+ iFrameNumber(aSrc.iFrameNumber),
+ iFrameCount(0),
+ iFrameInterval(0)
+ {
+ SetFileName(*aSrc.iFileName);
+ }
+
+CHuiTextureManager::CTextureEntry & CHuiTextureManager::CTextureEntry::operator=(const CTextureEntry &aSrc)
+ {
+ if ( this == &aSrc )
+ {
+ return *this;
+ }
+
+ iId = aSrc.iId;
+ if (aSrc.iFileName != NULL)
+ {
+ SetFileName(*aSrc.iFileName);
+ }
+ iMaxTextureSize = aSrc.iMaxTextureSize;
+ iFlags = aSrc.iFlags;
+ iBitmapProvider = aSrc.iBitmapProvider;
+ iFrameNumber = aSrc.iFrameNumber;
+ iFrameCount = aSrc.iFrameCount;
+ iFrameInterval = aSrc.iFrameInterval;
+ return *this;
+ }
+
+EXPORT_C CHuiTextureManager::CTextureEntry::~CTextureEntry()
+ {
+ delete iFileName;
+ iFileName = NULL;
+ // CHuiTextureManager deletes the iTexture
+ }
+
+void CHuiTextureManager::CTextureEntry::SetFileName(const TFileName & aFileName)
+ {
+ delete iFileName;
+ iFileName = NULL;
+ if (aFileName.Length()>0)
+ {
+ // this might fail and therefore the iFileName is left as NULL.
+ iFileName = aFileName.Alloc();
+ }
+ }
+
+void CHuiTextureManager::CTextureEntry::TextureContentUploaded(CHuiTexture& /*aTexture*/)
+ {
+ }
+void CHuiTextureManager::CTextureEntry::TextureContentReleased(CHuiTexture& /*aTexture*/)
+ {
+ }
+void CHuiTextureManager::CTextureEntry::RestoreTextureContentL(CHuiTexture& aTexture)
+ {
+ HUI_DEBUG(_L("CHuiTextureManager::CTextureEntry::RestoreTextureContentL() - Called for entry 0x%x (id: %i)."));
+ if (iBitmapProvider != NULL)
+ {
+ HUI_DEBUG3(_L("CHuiTextureManager::CTextureEntry::RestoreTextureContentL() - Using bitmap provider 0x%x to recreate content for texture 0x%x (id: %i).."), iBitmapProvider, &aTexture, iId);
+ CFbsBitmap* bitmap = NULL;
+ CFbsBitmap* maskBitmap = NULL;
+
+ // call the bitmapProvider method to load the bitmaps
+ iBitmapProvider->ProvideBitmapL(iId, bitmap, maskBitmap);
+
+ if (maskBitmap)
+ {
+ CleanupStack::PushL(maskBitmap);
+ }
+
+ if (!bitmap)
+ {
+ User::Leave(KErrArgument);
+ }
+ else
+ {
+ CleanupStack::PushL(bitmap);
+ }
+
+ // recreate texture content..
+
+ // Let the texture know its size as soon as possible.
+ aTexture.SetSize(bitmap->SizeInPixels());
+
+ // Enable texture shadow.
+ aTexture.EnableShadow((iFlags & EHuiTextureUploadFlagGenerateShadow) != 0);
+
+ // Upload!
+ TSize bitmapSize = bitmap->SizeInPixels();
+ if (bitmapSize.iWidth != 0 && bitmapSize.iHeight != 0)
+ {
+ if (iFlags & EHuiTextureFlagAllowDirectBitmapUsage)
+ {
+ aTexture.UploadDirectL(*bitmap, maskBitmap, iFlags);
+ }
+ else
+ {
+ aTexture.UploadL(*bitmap, maskBitmap, iFlags);
+ }
+ }
+ // Clean up owned bitmaps
+ CleanupStack::PopAndDestroy(bitmap);
+ if (maskBitmap)
+ {
+ CleanupStack::PopAndDestroy(maskBitmap);
+ }
+ }
+ // check for file-based restore
+ else if (iFileName != NULL)
+ {
+ HUI_DEBUG2(_L("CHuiTextureManager::CTextureEntry::RestoreTextureContentL() - Reloading texture 0x%x from \"%S\".."), &aTexture, iFileName);
+ CHuiStatic::Env().TextureManager().LoadTextureL(*iFileName, iMaxTextureSize, iFlags, iId);
+ return;
+ }
+ else
+ {
+ // for PC lint
+ }
+ }
+
+void CHuiTextureManager::NotifyTextureAutoSizeObservers() const
+ {
+ if (!iTextureAutoSizingEnabled)
+ {
+ return;
+ }
+
+ TBool somethingWasReported = EFalse;
+ TBool anyAutoSizedTexturesExist = EFalse;
+
+ for(TInt index = iTextures.Count() - 1; index >= 0; --index)
+ {
+ CTextureEntry * entry = iTextures[index];
+ if (entry->iTexture)
+ {
+ if (entry->iTexture->IsAutoSizeCalculationEnabled())
+ {
+ anyAutoSizedTexturesExist = ETrue;
+
+ // Calculate preferred size from the previous frame data
+ THuiRealSize preferredSize = entry->iTexture->CalculateAutoSize();
+
+ // Notify observers if preferred size has changed
+ if (entry->iTexture->CalculatedAutoSizeChanged())
+ {
+ HUI_DEBUG3(_L("CHuiTextureManager::NotifyTexturePreferredSizeObservers - To be notified id: %i, width: %f , height %f"), entry->iId, preferredSize.iWidth, preferredSize.iHeight);
+
+ // Notify observers. For now ignore return values.
+ for(TInt index = 0; index < iTextureAutoSizeObservers.Count(); ++index)
+ {
+ iTextureAutoSizeObservers[index].PreferredSizeChanged(*entry->iTexture, entry->iId, preferredSize);
+ somethingWasReported = ETrue;
+ }
+ }
+
+ // Restart preferred size calculations for next frame
+ entry->iTexture->ResetAutoSizeCalculation();
+ }
+ }
+ }
+
+ if (somethingWasReported)
+ {
+ for(TInt index = 0; index < iTextureAutoSizeObservers.Count(); ++index)
+ {
+ iTextureAutoSizeObservers[index].PreferredSizeReportCompleted();
+ }
+ }
+
+ // Keep checking autosized textures only if those exist.
+ // New textures will enable flag when needed.
+ iTextureAutoSizingEnabled = anyAutoSizedTexturesExist;
+ }
+
+EXPORT_C void CHuiTextureManager::ClearChangedTextures()
+ {
+ if (iHasChangedTextures)
+ {
+ for(TInt index = iTextures.Count() - 1; index >= 0; --index)
+ {
+ CTextureEntry * entry = iTextures[index];
+ if (entry->iTexture)
+ {
+ entry->iTexture->TextureClearChanged();
+ }
+ }
+ iHasChangedTextures = EFalse;
+ }
+ }
+
+EXPORT_C void CHuiTextureManager::SetHasChangedTextures()
+ {
+ iHasChangedTextures = ETrue;
+ }
+
+/*
+ * Enables/Disables memory usage calculation.
+ */
+EXPORT_C void CHuiTextureManager::EnableTexMemoryCalculation( TBool aEnableTeMemCal )
+ {
+ iEnableTexMemCalculation = aEnableTeMemCal;
+ }
+
+/*
+ * Calculates memory used by texturemanager to store all the textures.
+ * Texture memory is calculated as ( Texture area ) * ( bits per pixel )
+ *
+ * This routine prints info message stating toal no of textures and memory consuption by them.
+ */
+void CHuiTextureManager::TextureMemUsage() const
+ {
+ TReal32 totalMemUsage = 0;
+ TReal32 avgBitDepth = 0;
+ for(TInt i = 0; i < iTextures.Count(); ++i)
+ {
+ if( iTextures[i]->iTexture )
+ {
+ TSize size = iTextures[i]->iTexture->Size();
+ totalMemUsage = totalMemUsage + size.iWidth * size.iHeight * iTextures[i]->iBitDepth;
+ avgBitDepth = avgBitDepth + iTextures[i]->iBitDepth;
+ }
+ }
+
+ avgBitDepth = avgBitDepth/iTextures.Count();
+ totalMemUsage = totalMemUsage/8000000;
+ TBuf<300> buf;
+ buf.FillZ();
+ buf.AppendNum( totalMemUsage, TRealFormat( 8, 4 ) );
+ buf.Append(_L( "MB;By:" ) );
+ buf.AppendNum( iTextures.Count() );
+ buf.Append(_L( ";BD:" ) );
+ buf.AppendNum( avgBitDepth );
+ User::InfoPrint( buf );
+ }
+TInt CHuiTextureManager::EstimatedTextureMemUsage(TInt aAverageBitsPerPixel) const
+ {
+ TReal32 averageBytesPerPixel = TReal32(aAverageBitsPerPixel)/8.f;
+ TReal32 totalMemUsage = 0;
+ TInt pixels = 0;
+ for(TInt i = 0; i < iTextures.Count(); ++i)
+ {
+ // TODO: Exclude NVG textures !
+ if( iTextures[i]->iTexture /*&&
+ iTextures[i]->iTexture->HasContent()*/)
+ {
+ TSize size = iTextures[i]->iTexture->Size();
+ pixels += size.iWidth * size.iHeight;
+ }
+ }
+
+ totalMemUsage = TReal32(pixels) * averageBytesPerPixel;
+ return totalMemUsage;
+ }
+
+
+
+EXPORT_C void CHuiTextureManager::TextureManagerExtension(const TUid& /*aExtensionUid*/, TAny** aExtensionParams)
+ {
+ // If no extension with given UID was found, indicate it by returning null
+ *aExtensionParams = NULL;
+ }
+
+void CHuiTextureManager::EnableAutoSizeCalculation(TBool aEnable)
+ {
+ iTextureAutoSizingEnabled = aEnable;
+ }
+