/*
* 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.
TRAP_IGNORE( 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;
}