/*
* Copyright (c) 2006 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: Loads textures.
*
*/
#include <e32std.h>
#include <imageconversion.h>
#include <eikenv.h>
#include <eikappui.h>
#include <eikapp.h>
#include "alf/alftexturemanager.h"
#include "alf/alftextureprocessor.h"
#include "alf/alftexture.h"
#include "alf/alfenv.h"
#include "alfclient.h"
#include "alf/alfutil.h"
#include "alf/alfbitmapprovider.h"
#include "alflogger.h"
const TInt KFirstAutoGeneratedTextureId = 0x10000000;
const TInt KAlfDefaultSizeDimension = 4;
/**
* Flag to indicate to use the provided bitmap directly for the texture, without conversion or copying. The bitmaps
* should be in the correct format and they shall not be compressed or have duplicated handle.
* If the direct bitmap cannot be used, this flag is ignored internally.
*
* NOTE: This flag is not a public since we cannot guarantee that user does not compress
* bitmap or otherwise temper with it after providing it to toolkit.
* But internally we can use this in some cases to speed up the texture upload.
*
*/
enum
{
EAlfTextureFlagAllowDirectBitmapUsage = 0x20
};
struct TTextureEntry
{
public:
~TTextureEntry()
{
}
TTextureEntry()
: iId(0), iTexture(NULL), iRefCount(-1)
{
}
TTextureEntry(TInt aId,
CAlfTexture* aTexture)
: iId(aId), iTexture(aTexture),iRefCount(-1)
{
}
/** The texture id. Set to zero for no id. */
TInt iId;
/** The texture entry. */
CAlfTexture* iTexture;
/** Reference count. */
TInt iRefCount;
};
struct TLoadQueueEntry
{
/** The texture entry that is being loaded. */
TTextureEntry iLoading;
/** The image being loaded has an alpha channel. */
TBool iHasAlpha;
/** The original, non-downscaled size of the image. */
TSize iOriginalSize;
/** Image decoder to load bitmap images. */
CImageDecoder* iDecoder;
/** True, if the texture was already unloaded before it finished
loading. */
TBool iUnloaded;
};
// Private structure
struct CAlfTextureManager::TPrivateData
{
CAlfEnv* iEnv; // Not owned.
/**
* Registry of all textures within this toolkit.
* Accessed by texture ids (iId).
*/
RArray<TTextureEntry> iTextures;
/** Queue of loading tasks. */
RArray<TLoadQueueEntry> iLoadQueue;
/** Queue of loading observers. */
RPointerArray<MAlfTextureLoadingCompletedObserver> iLoadObserverQueue;
/** Queue of state observers. */
RPointerArray<MAlfTextureManagerStateChangedObserver> iStateObserverQueue;
/** Blank texture */
CAlfTexture* iBlankTexture;
/** Path where image files are loaded from. */
HBufC* iImagePath;
/** State of the texture manager. */
TState iState;
/** Bitmap for loading asynchronously into. */
CFbsBitmap* iBitmap;
/** Mask bitmap for loading alpha channels. */
CFbsBitmap* iMaskBitmap;
/** Open file server session for image loading. */
RFs iFs;
/** Id of this texture manager. */
TUid iManagerId;
/** Texture processor */
CAlfTextureProcessor* iProcessor;
/** Texture id auto generation */
TInt iAutoGeneratedTextureId;
TInt iLowestAutoGeneratedTextureId;
TInt iHighestAutoGeneratedTextureId;
RPointerArray<MAlfTextureAutoSizeObserver> iAutoSizeObserverQueue;
// DEBUG
TBool iTextureAutoCounterEnabled;
TInt iTextureAutoRecreateCounter;
TInt iTextureAutoReloadCounter;
//...add other member variables...
CIdle* iDoomBringer;
};
// ======== MEMBER FUNCTIONS ========
// ---------------------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------------------
//
CAlfTextureManager::CAlfTextureManager() : CActive(EPriorityHigh)
{
}
// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//
CAlfTextureManager::~CAlfTextureManager()
{
Cancel();
if ( iData )
{
delete iData->iImagePath;
delete iData->iBlankTexture;
RArray<TTextureEntry>& textures = (iData->iTextures);
// Remove all texture entries (from last to first -order)
while (textures.Count())
{
TTextureEntry te = textures[textures.Count()-1];
delete te.iTexture;
te.iTexture = NULL;
}
textures.Close();
iData->iLoadQueue.Close();
iData->iLoadObserverQueue.Close();
iData->iStateObserverQueue.Close();
iData->iAutoSizeObserverQueue.Close();
delete iData->iBitmap;
delete iData->iMaskBitmap;
iData->iFs.Close();
delete iData->iProcessor;
if (iData->iDoomBringer)
iData->iDoomBringer->Cancel();
delete iData->iDoomBringer;
}
delete iData;
}
// ---------------------------------------------------------------------------
// NewL
// ---------------------------------------------------------------------------
//
CAlfTextureManager* CAlfTextureManager::NewL(CAlfEnv& aEnv, TUid aUid)
{
CAlfTextureManager* self = CAlfTextureManager::NewLC(aEnv, aUid);
CleanupStack::Pop( self );
return self;
}
// ---------------------------------------------------------------------------
// NewLC
// ---------------------------------------------------------------------------
//
CAlfTextureManager* CAlfTextureManager::NewLC(CAlfEnv& aEnv, TUid aUid)
{
CAlfTextureManager* self = new( ELeave ) CAlfTextureManager();
CleanupStack::PushL( self );
self->ConstructL(aEnv, aUid);
return self;
}
// ---------------------------------------------------------------------------
// 2nd phase constructor
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::ConstructL(CAlfEnv& aEnv, TUid aUid)
{
iData = new (ELeave) TPrivateData;
// Zero all data
iData->iEnv = NULL;
iData->iTextures.Reset();
iData->iLoadQueue.Reset();
iData->iLoadObserverQueue.Reset();
iData->iAutoSizeObserverQueue.Reset();
iData->iBlankTexture = NULL;
iData->iImagePath = NULL;
iData->iState = EIdle;
iData->iBitmap = NULL;
iData->iMaskBitmap = NULL;
iData->iManagerId = TUid::Uid(0);
iData->iProcessor = NULL;
// Fill data
iData->iAutoGeneratedTextureId = KFirstAutoGeneratedTextureId;
iData->iLowestAutoGeneratedTextureId = KFirstAutoGeneratedTextureId;
iData->iHighestAutoGeneratedTextureId = KMaxTInt;
iData->iEnv = &aEnv;
iData->iManagerId = aUid;
iData->iBlankTexture = CAlfTexture::NewL(aEnv, aUid);
iData->iBitmap = new (ELeave) CFbsBitmap();
User::LeaveIfError(iData->iBitmap->Create(
TSize(KAlfDefaultSizeDimension, KAlfDefaultSizeDimension), EColor64K));
iData->iMaskBitmap = new (ELeave) CFbsBitmap();
User::LeaveIfError(iData->iMaskBitmap->Create(
TSize(KAlfDefaultSizeDimension, KAlfDefaultSizeDimension), EGray256));
iData->iProcessor = CAlfTextureProcessor::NewL(aEnv);
User::LeaveIfError(iData->iFs.Connect());
iData->iDoomBringer = CIdle::NewL(CActive::EPriorityIdle);
// DEBUG
iData->iTextureAutoCounterEnabled = EFalse;
iData->iTextureAutoRecreateCounter = 0;
iData->iTextureAutoReloadCounter = 0;
SetImagePathL(_L(""));
CActiveScheduler::Add(this);
}
// ---------------------------------------------------------------------------
// Returns env
// ---------------------------------------------------------------------------
//
EXPORT_C CAlfEnv& CAlfTextureManager::Env()
{
return *iData->iEnv;
}
// ---------------------------------------------------------------------------
// Returns texture with given id
// ---------------------------------------------------------------------------
//
EXPORT_C const CAlfTexture* CAlfTextureManager::Texture(TInt aId) const
{
TInt index = CheckTexture(aId);
if(index == KErrNotFound)
{
return &BlankTexture();
}
RArray<TTextureEntry>& textures = (iData->iTextures);
CAlfTexture* texture = textures[index].iTexture;
if(texture)
{
return texture;
}
else
{
return &BlankTexture();
}
}
// ---------------------------------------------------------------------------
// Returns texture with given id
// ---------------------------------------------------------------------------
//
EXPORT_C CAlfTexture* CAlfTextureManager::TextureL(TInt aId)
{
// try to get the index for the texture id
TInt index = CheckTexture(aId);
if(index != KErrNotFound)
{
// texture found
RArray<TTextureEntry>& textures = (iData->iTextures);
CAlfTexture* texture = textures[index].iTexture;
if(texture == NULL)
{
User::Leave(KErrNotFound);
return NULL;
}
return texture;
}
User::Leave(KErrNotFound);
return NULL;
}
// ---------------------------------------------------------------------------
// Sets image path
// ---------------------------------------------------------------------------
//
EXPORT_C void CAlfTextureManager::SetImagePathL(const TDesC& aPath)
{
delete iData->iImagePath;
iData->iImagePath = NULL;
TParsePtrC parse(aPath);
CEikonEnv* coe = CEikonEnv::Static();
if (aPath.Length() && !parse.DrivePresent() && coe && coe->EikAppUi() && coe->EikAppUi()->Application())
{
iData->iImagePath = HBufC::NewL(aPath.Size()+2); // two extra characters for drive
TPtr ptr = iData->iImagePath->Des();
ptr.Append(coe->EikAppUi()->Application()->AppFullName().Left(2));
ptr.Append(aPath);
}
else
{
iData->iImagePath = aPath.AllocL();
}
}
// ---------------------------------------------------------------------------
// Gets image path
// ---------------------------------------------------------------------------
//
EXPORT_C const TDesC& CAlfTextureManager::ImagePath() const
{
return *iData->iImagePath;
}
// ---------------------------------------------------------------------------
// Returns blank texture.
// ---------------------------------------------------------------------------
//
EXPORT_C const CAlfTexture& CAlfTextureManager::BlankTexture() const
{
return *iData->iBlankTexture;
}
// ---------------------------------------------------------------------------
// Returns blank texture.
// ---------------------------------------------------------------------------
//
EXPORT_C CAlfTexture& CAlfTextureManager::BlankTexture()
{
return *iData->iBlankTexture;
}
// ---------------------------------------------------------------------------
// DEPRECATED! Load the animated texture based on the Skin name
// ---------------------------------------------------------------------------
//
EXPORT_C CAlfTexture& CAlfTextureManager::LoadAnimatedTextureL(const TDesC& /*aSkinAnimName*/,
TSize /*aTextureMaxSize*/,
TAlfTextureFlags /*aFlags*/,
TInt /*aId*/)
{
__ALFLOGSTRING( "CAlfTextureManager::LoadAnimatedTextureL FUNCTIONALITY REMOVED. REFER TO ANTRIKSH PROJECT" );
CAlfTexture* tex = NULL;
return *tex;
}
// Loads texture.
// ---------------------------------------------------------------------------
//
EXPORT_C CAlfTexture& CAlfTextureManager::LoadTextureL(const TDesC& aImageName,
TAlfTextureFlags aFlags,
TInt aId)
{
return LoadTextureL(aImageName, TSize(0, 0), aFlags, aId);
}
// ---------------------------------------------------------------------------
// Loads texture.
// ---------------------------------------------------------------------------
//
EXPORT_C CAlfTexture& CAlfTextureManager::LoadTextureL(const TInt aId,
TSize aTextureMaxSize,
TAlfTextureFlags aFlags)
{
return LoadTextureL(_L(""), aTextureMaxSize, aFlags, aId);
}
// ---------------------------------------------------------------------------
// Loads texture.
// ---------------------------------------------------------------------------
//
EXPORT_C CAlfTexture& CAlfTextureManager::LoadTextureL(const TDesC& aImageName,
TSize aTextureMaxSize,
TAlfTextureFlags aFlags,
TInt aId)
{
// Clients are not allowed to let toolkit use bitmaps directly.
// We could use it internally if we had separate bitmaps
// for each entry.
RemoveFlags(aFlags, EAlfTextureFlagAllowDirectBitmapUsage);
if (aId == KAlfAutoGeneratedTextureId)
{
aId = GenerateTextureId();
}
CAlfTexture* tex = NULL;
TFileName fileName;
// Provide an already created texture if such exists.
TRAPD(err, tex = TextureL(aId));
if(err == KErrNone && tex->HasContent())
{
return *tex;
}
// If shared texture manager, then check the existense of the texture first.
if (IsShared())
{
// AutoSize is not supported (yet) for shared textures
RemoveFlags(aFlags, EAlfTextureFlagAutoSize);
TBool sharedTextureAlreadyExists = EFalse;
iData->iEnv->Client().TextureHasContent(sharedTextureAlreadyExists,
aId,
iData->iManagerId.iUid);
// If shared texture already exists, we don't even start to load it.
if (sharedTextureAlreadyExists)
{
TInt bitmapHandle = 0;
TInt maskHandle = 0;
if (iData->iBitmap)
{
bitmapHandle = iData->iBitmap->Handle();
}
if (iData->iMaskBitmap)
{
maskHandle = iData->iMaskBitmap->Handle();
}
// Create CAlfTexture instance.
tex = CAlfTexture::NewL( Env(),
iData->iManagerId,
aId,
bitmapHandle,
maskHandle,
aFlags);
if(aImageName.Length() > 0)
{
// assume relative pathname and prepend the image path to get full filename
fileName = aImageName;
PrependImagePath(fileName);
tex->SetFileNameL(fileName);
}
tex->SetMaxTextureSize(aTextureMaxSize);
return *tex;
}
}
// If the name is invalid, and there was no filename available
// based on id, return a dummy texture.
if((aImageName.Length() == 0) && (aId == 0))
{
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
// there's and nonzero id has been passed, we
// can assume that there's a predefined name available
RArray<TTextureEntry>& textures = (iData->iTextures);
RArray<TLoadQueueEntry>& loadqueue = (iData->iLoadQueue);
if((aImageName.Length() == 0) && (aId != 0))
{
// search for a texture filename based on the id.
TInt index = CheckTexture(aId);
if(index >=0)
{
tex = textures[index].iTexture;
fileName = *tex->FileName();
}
else
{
User::Leave(KErrNotFound);
}
}
// Reuse pre-existing entries:
// try first finding an entry based on id
if(!tex && aId > 0)
{
TInt previouslyLoadedIndex = CheckTexture(aId);
if (previouslyLoadedIndex >= 0)
{
tex = textures[previouslyLoadedIndex].iTexture;
}
}
if (!tex)
{
TInt bitmapHandle = 0;
TInt maskHandle = 0;
// If LoadAnimAsImage flag is set, we don't check the framecount with ImageDecoder!
//
// This is useful especially when loading multiple large image files
// as textures that don't have more then 1 frame.
//
// Some test results creating the ImageDecoder:
// - Large Leafs.mbm (2,7MB) took apporx. 280ms
// - Big bmp (~1,8MB) took ~130ms
// - Normal sized (100-800kb) jpgs and gifs took approx. 25-40ms
TInt frameCount = 1;
TSize animFrameSize = TSize(0,0);
if ( !(aFlags & EAlfTextureFlagLoadAnimAsImage) )
{
CImageDecoder* decoder = CImageDecoder::FileNewL(iData->iFs, fileName);
CleanupStack::PushL(decoder);
frameCount = decoder->FrameCount();
if (frameCount > 1)
{
const TFrameInfo& fInfo = decoder->FrameInfo(0);
animFrameSize = fInfo.iOverallSizeInPixels;
}
CleanupStack::PopAndDestroy();
}
if (frameCount > 1)
{
tex = CAlfTexture::NewL(Env(), iData->iManagerId, aId, bitmapHandle, maskHandle, aFlags, ETrue);
tex->SetMaxTextureSize(aTextureMaxSize);
tex->SetSize(animFrameSize);
tex->SetFileNameL(fileName);
return *tex;
}
else
{
if (iData->iBitmap)
{
bitmapHandle = iData->iBitmap->Handle();
}
if (iData->iMaskBitmap)
{
maskHandle = iData->iMaskBitmap->Handle();
}
tex = CAlfTexture::NewL(Env(), iData->iManagerId, aId, bitmapHandle, maskHandle, aFlags);
}
}
else
{
// we have a pre-existing texture which is non-null,
// but check that the texture is loaded ok, we can also
// return unloaded textures that are in the load queue
if (tex->HasContent() || tex->IsAnimated() || IsInLoadQueue(tex))
{
return *(tex);
}
}
// replace filename
// File names are relative to the image path.
tex->SetFileNameL(fileName);
tex->SetMaxTextureSize(aTextureMaxSize);
// Set not released
tex->SetReleaseFlags(CAlfTexture::EReleaseNone);
// If autosize used and size is set to zero, we don't yet load at all.
if (aFlags & EAlfTextureFlagAutoSize)
{
if (aTextureMaxSize.iHeight == 0 && aTextureMaxSize.iWidth == 0)
{
return *tex;
}
}
// Prepare for loading by creating a load queue entry.
TTextureEntry entry;
entry.iTexture = tex;
entry.iId = aId;
TLoadQueueEntry loadqentry;
loadqentry.iUnloaded = EFalse;
loadqentry.iLoading = entry;
loadqentry.iDecoder = NULL;
// Textures are loaded one at a time, in the order they were requested.
loadqueue.AppendL(loadqentry);
// Start the texture load active object if we're not loading
if(iData->iState == EIdle)
{
// Start loading images..
StartLoading();
// Notify observers.
NotifyStateChange();
}
return *tex;
}
// ---------------------------------------------------------------------------
// Creates texture.
// ---------------------------------------------------------------------------
//
EXPORT_C CAlfTexture& CAlfTextureManager::CreateTextureL(TInt aId,
MAlfBitmapProvider* aBitmapProvider,
TAlfTextureFlags aFlags)
{
// Clients are not allowed to let toolkit use bitmaps directly. It is used only internally.
RemoveFlags(aFlags, EAlfTextureFlagAllowDirectBitmapUsage);
CAlfTexture* tex = NULL;
if (aId == KAlfAutoGeneratedTextureId)
{
aId = GenerateTextureId();
}
CFbsBitmap* bitmap = NULL;
CFbsBitmap* maskBitmap = NULL;
if (aId==0)
{
User::Leave(KErrArgument);
}
// Provide an already created texture if such exists.
TRAPD(err, tex = TextureL(aId));
if(err == KErrNone && tex->HasContent())
{
return *tex;
}
// Call the bitmapProvider method to load the bitmaps
if (aBitmapProvider)
{
aBitmapProvider->ProvideBitmapL(aId, bitmap, maskBitmap);
}
if (!bitmap)
{
// We leave here, otherwise serverside would panic.
User::Leave(KErrArgument);
// Bitmap size is checked and handled in serverside,
// so that we can create empty textures (size = 0,0)
}
// "bitmap" pointer should be valid from now on
CleanupStack::PushL(bitmap);
TInt bitmapHandle = bitmap->Handle();
TInt maskHandle = 0;
if (maskBitmap)
{
maskHandle = maskBitmap->Handle();
CleanupStack::PushL(maskBitmap);
}
// Create CAlfTexture instance, this duplicates the bitmaps to server.
if (!tex)
{
tex = CAlfTexture::NewL( Env(),
iData->iManagerId,
aId,
bitmapHandle,
maskHandle,
aFlags);
}
else
{
// texture already exists but it does not have content, this creates content.
iData->iEnv->Client().TextureCreateL( aId, bitmapHandle,
maskHandle, aFlags, iData->iManagerId.iUid );
}
tex->SetBitmapProvider(aBitmapProvider);
tex->SetSize(bitmap->SizeInPixels());
// Set not released
tex->SetReleaseFlags(CAlfTexture::EReleaseNone);
// CAlfTexture has at this point duplicated bitmaps, can be deleted here.
if (maskBitmap)
{
CleanupStack::PopAndDestroy( maskBitmap );
maskBitmap = NULL;
}
CleanupStack::PopAndDestroy( bitmap );
bitmap = NULL;
// Notify observers
NotifyTextureLoaded(*tex, aId, KErrNone);
return *tex;
}
// ---------------------------------------------------------------------------
// Unloads texture
// ---------------------------------------------------------------------------
//
EXPORT_C void CAlfTextureManager::UnloadTexture(const TDesC& aImageName)
{
TInt index = CheckTexture(aImageName);
if (index >= 0)
{
RArray<TTextureEntry>& textures = (iData->iTextures);
TTextureEntry entry = textures[index];
CancelLoadingOfTexture(*entry.iTexture);
if (!entry.iTexture->IsAnimated())
{
iData->iEnv->Client().TextureUnload(entry.iId, iData->iManagerId.iUid);
}
else
{
entry.iTexture->StopAnimation();
}
TInt releaseFlags = entry.iTexture->ReleaseFlags();
releaseFlags |= CAlfTexture::EReleaseFromUnload;
entry.iTexture->SetReleaseFlags(releaseFlags);
}
}
// ---------------------------------------------------------------------------
// Unloads texture
// ---------------------------------------------------------------------------
//
EXPORT_C void CAlfTextureManager::UnloadTexture(TInt aId)
{
TInt index = CheckTexture(aId);
if (index >= 0)
{
RArray<TTextureEntry>& textures = (iData->iTextures);
TTextureEntry entry = textures[index];
CancelLoadingOfTexture(*entry.iTexture);
if (!entry.iTexture->IsAnimated())
{
iData->iEnv->Client().TextureUnload( aId, iData->iManagerId.iUid );
}
else
{
entry.iTexture->StopAnimation();
}
TInt releaseFlags = entry.iTexture->ReleaseFlags();
releaseFlags |= CAlfTexture::EReleaseFromUnload;
entry.iTexture->SetReleaseFlags(releaseFlags);
}
}
// ---------------------------------------------------------------------------
// Updates texture content
// ---------------------------------------------------------------------------
//
EXPORT_C void CAlfTextureManager::UpdateTextureFromFileL(TInt aId, const TDesC* aFileName)
{
RArray<TTextureEntry>& textureEntries = (iData->iTextures);
TInt index = CheckTexture(aId);
if (index >= 0)
{
TTextureEntry entry = textureEntries[index];
TFileName fileName;
if (aFileName != NULL)
{
fileName = *aFileName;
}
else if (entry.iTexture->FileName() == NULL)
{
User::Leave(KErrArgument);
}
entry.iTexture->SetBitmapProvider(NULL);
// Set non released
entry.iTexture->SetReleaseFlags(CAlfTexture::EReleaseNone);
if (!entry.iTexture->IsAnimated())
{
ReloadTextureL(fileName, entry.iTexture->MaxTextureSize(), entry.iTexture->Flags(),
entry.iTexture->Id());
}
else
{
entry.iTexture->StartAnimation();
}
}
else
{
User::Leave(KErrNotFound);
}
}
// ---------------------------------------------------------------------------
// Updates texture content
// ---------------------------------------------------------------------------
//
EXPORT_C void CAlfTextureManager::UpdateTextureFromBitmapL(TInt aId, MAlfBitmapProvider* aBitmapProvider)
{
RArray<TTextureEntry>& textureEntries = (iData->iTextures);
TInt index = CheckTexture(aId);
if (index >= 0)
{
TTextureEntry entry = textureEntries[index];
if (!aBitmapProvider)
{
aBitmapProvider = entry.iTexture->BitmapProvider();
}
TBuf<1> empty;
entry.iTexture->SetFileNameL(empty);
// Set non released
entry.iTexture->SetReleaseFlags(CAlfTexture::EReleaseNone);
if (!entry.iTexture->IsAnimated())
{
RecreateTextureL(entry.iTexture->Id(), aBitmapProvider, entry.iTexture->Flags());
}
else
{
entry.iTexture->StartAnimation();
}
}
else
{
User::Leave(KErrNotFound);
}
}
// ---------------------------------------------------------------------------
// Defines filename for given id.
// ---------------------------------------------------------------------------
//
EXPORT_C void CAlfTextureManager::DefineFileNameL(TInt aId, const TDesC& aFileName)
{
if (aId==0)
{
User::Leave(KErrArgument); // can't specify filename for "no id"
}
RArray<TTextureEntry>& textures = (iData->iTextures);
// Look for an existing entry for the id.
for(TInt i = 0; i < textures.Count(); ++i)
{
if(textures[i].iId == aId)
{
textures[i].iTexture->SetFileNameL(aFileName);
return;
}
}
// Otherwise just append to the texture list
CAlfTexture* tex = CAlfTexture::NewL( Env(), iData->iManagerId, aId );
tex->SetFileNameL(aFileName);
}
// ---------------------------------------------------------------------------
// Prepends image path
// ---------------------------------------------------------------------------
//
EXPORT_C void CAlfTextureManager::PrependImagePath(TDes& aFileName)
{
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(*iData->iImagePath) == KErrNotFound)
{
buf = *iData->iImagePath;
buf.Append(aFileName);
aFileName = buf;
}
}
// ---------------------------------------------------------------------------
// CheckTexture
// ---------------------------------------------------------------------------
//
TInt CAlfTextureManager::CheckTexture(const TDesC& aImageName) const
{
if(aImageName.Length()==0)
{
// name empty, can't check
return KErrNotFound;
}
RArray<TTextureEntry>& textures = (iData->iTextures);
for(TInt i = 0; i < textures.Count(); ++i)
{
TTextureEntry te = textures[i];
// compare against texture manager entry filename (iFileName)
if((te.iTexture->FileName() != NULL)
&& (aImageName.Compare(*(te.iTexture->FileName())) == 0))
{
return i;
}
}
// not found
return KErrNotFound;
}
// ---------------------------------------------------------------------------
// CheckTexture
// ---------------------------------------------------------------------------
//
TInt CAlfTextureManager::CheckTexture(TInt aId) const
{
RArray<TTextureEntry>& textures = (iData->iTextures);
if(aId <= 0)
{
// id not defined, can't search
return KErrNotFound;
}
for(TInt i = 0; i < textures.Count(); i++)
{
if(textures[i].iId == aId)
{
return i;
}
}
// not found:
return KErrNotFound;
}
// ---------------------------------------------------------------------------
// RunError from CActive
// ---------------------------------------------------------------------------
//
TInt CAlfTextureManager::RunError(TInt /*aError*/)
{
return KErrNone;
// Should never be called, RunL is responsible for handling all error cases
}
// ---------------------------------------------------------------------------
// RunL from CActive
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::RunL()
{
// remove the loaded entry from the queue
TLoadQueueEntry entry = PopLoadedQueueEntry();
// Image loading has been completed.
iData->iState = EIdle;
// check status
if(iStatus == 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)
{
// Notify observers about the image upload error
NotifyTextureLoaded(*entry.iLoading.iTexture, entry.iLoading.iId, err);
}
}
else
{
// notify sb of failed image load!
NotifyTextureLoaded(*entry.iLoading.iTexture, entry.iLoading.iId, iStatus.Int());
}
StartLoading();
}
// ---------------------------------------------------------------------------
// Cancels asyncronous loading
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::DoCancel()
{
RArray<TLoadQueueEntry>& loadqueue = (iData->iLoadQueue);
if(loadqueue.Count() > 0)
{
loadqueue[0].iDecoder->Cancel();
}
iData->iState = EIdle;
}
// ---------------------------------------------------------------------------
// Starts asyncronous loading
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::StartLoading()
{
// loop that finds next entry to load
while (1)
{
// try to schedule next image for loading..
TRAPD( err, DoLoadNextL() );
// ok?
if(err != KErrNone)
{
// remove the entry from the queue
TLoadQueueEntry entry = PopLoadedQueueEntry();
// Notify observers about the image loading error
NotifyTextureLoaded(*entry.iLoading.iTexture, entry.iLoading.iId, err);
// Image loading has been completed.
iData->iState = EIdle;
continue;
}
// leave the loop if we had no trouble scheduling the next
// image decode
break;
}
}
// ---------------------------------------------------------------------------
// Loads texture entry from queue. Mostly this code is copied from
// CAlfTextureManager::DoLoadNextL but some adjustmets has been made to support
// better client server paradigm.
//
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::DoLoadNextL()
{
RArray<TLoadQueueEntry>& loadqueue = (iData->iLoadQueue);
// Any loading tasks left?
if(loadqueue.Count() == 0)
{
// No? Notify observers and leave.
NotifyStateChange();
return; // nothing else to be loaded..
}
// Manager is now busy.
iData->iState = ELoading;
// Fetch a load queue entry
TLoadQueueEntry& entry = loadqueue[0];
CAlfTexture* texture = entry.iLoading.iTexture;
// Create a new image decoder for loading the image.
TFileName imageFileName = *texture->FileName(); // does not include image path
PrependImagePath(imageFileName);
entry.iDecoder = 0;
// We use fast decode because it seems to be a lot faster with jpegs.
TRAPD( err, entry.iDecoder = CImageDecoder::FileNewL(iData->iFs, imageFileName, CImageDecoder::EPreferFastDecode ));
// check for errors..
if(err != KErrNone)
{
// Try to cancel the decoding (if possible)
if(entry.iDecoder)
{
entry.iDecoder->Cancel();
}
User::Leave(err); // re-leave with the error
}
// from decoder's frame info retrieve the framesize
TFrameInfo frameInfo(entry.iDecoder->FrameInfo(0));
// check for alpha channel
if(frameInfo.iFlags & TFrameInfo::ETransparencyPossible )
{
entry.iHasAlpha = ETrue;
}
else
{
entry.iHasAlpha = EFalse;
}
// Get the image original size
TRect bitmapSize = frameInfo.iFrameCoordsInPixels;
entry.iOriginalSize = bitmapSize.Size();
// target resolution for texture, initially equal to bitmap size
TInt widthResolutionTarget = bitmapSize.Size().iWidth;
TInt heightResolutionTarget = bitmapSize.Size().iHeight;
TSize maxTexSize = entry.iLoading.iTexture->MaxTextureSize();
// Assign new texture resolution target dimensions
// if we have explicitly requested them
if( (entry.iLoading.iTexture->Flags() & EAlfTextureFlagDoNotRetainResolution)
&& maxTexSize.iWidth > 0
&& maxTexSize.iHeight > 0)
{
// assign new target resolution for decoder-based scaling
if(maxTexSize.iWidth < widthResolutionTarget)
{
widthResolutionTarget = maxTexSize.iWidth;
}
if(maxTexSize.iHeight < heightResolutionTarget)
{
heightResolutionTarget = maxTexSize.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
}
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 the toolkit after the bitmap has been decoded
widthResolutionTarget = halvedWidth;
heightResolutionTarget = halvedHeight;
}
if (!(entry.iLoading.iTexture->Flags() & EAlfTextureFlagRetainColorDepth) &&
iData->iBitmap->DisplayMode()!=EColor64K)
{
// (Re)Create the bitmap in EColor64K (16bit) mode to save memory
iData->iBitmap->Create(TSize(widthResolutionTarget, heightResolutionTarget), EColor64K);
}
else if ((entry.iLoading.iTexture->Flags() & EAlfTextureFlagRetainColorDepth) &&
iData->iBitmap->DisplayMode()==EColor64K)
{
// (Re)Create the bitmap in EColor16MU (24bit) mode retain the color information
iData->iBitmap->Create(TSize(widthResolutionTarget, heightResolutionTarget), EColor16MU);
}
else
{
// no need to recreate the bitmap, but assign the new size!
iData->iBitmap->Resize(TSize(widthResolutionTarget, heightResolutionTarget));
}
if (iData->iBitmap->DisplayMode()==EColor64K)
{
}
// Decode ( and rescale ) to bitmap.
if(entry.iHasAlpha)
{
// set the alpha channel bitmap to the same size than the color bitmap
iData->iMaskBitmap->Resize(TSize(widthResolutionTarget, heightResolutionTarget));
entry.iDecoder->Convert(&iStatus, *iData->iBitmap, *iData->iMaskBitmap, 0);
}
else
{
// We cannot do resize mask to smaller until serverside works differently
iData->iMaskBitmap->Resize(TSize(widthResolutionTarget, heightResolutionTarget));
entry.iDecoder->Convert(&iStatus, *iData->iBitmap, 0);
}
// Wait for completion.
SetActive();
}
// ---------------------------------------------------------------------------
// Pops entry from load queue
// ---------------------------------------------------------------------------
//
TLoadQueueEntry CAlfTextureManager::PopLoadedQueueEntry()
{
RArray<TLoadQueueEntry>& loadqueue = (iData->iLoadQueue);
TLoadQueueEntry entry = loadqueue[0];
loadqueue.Remove(0);
// Delete the decoder.
delete entry.iDecoder;
entry.iDecoder = 0;
return entry;
}
// ---------------------------------------------------------------------------
// This method gets called when image loading has been completed and server
// side texture needs to be created.
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::ImageLoadingCompleteL(TLoadQueueEntry& aEntry)
{
TSize maxTexSize = aEntry.iLoading.iTexture->MaxTextureSize();
// Calculate new maxsize keeping the aspect ratio if only one max dimension was
// specified.
if ((maxTexSize.iWidth == 0 && maxTexSize.iHeight != 0) ||
(maxTexSize.iWidth != 0 && maxTexSize.iHeight == 0))
{
TSize sizeInPixels = iData->iBitmap->SizeInPixels();
if (sizeInPixels.iWidth != 0 && sizeInPixels.iHeight != 0)
{
if (maxTexSize.iWidth == 0)
{
maxTexSize.iWidth = (maxTexSize.iHeight * sizeInPixels.iWidth)/sizeInPixels.iHeight;
}
else if (maxTexSize.iHeight == 0)
{
maxTexSize.iHeight = (maxTexSize.iWidth * sizeInPixels.iHeight)/sizeInPixels.iWidth;
}
}
}
if( (maxTexSize.iWidth != 0) &&
(maxTexSize.iHeight != 0) &&
(iData->iBitmap->SizeInPixels() != aEntry.iLoading.iTexture->MaxTextureSize()))
{
// 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();
dest->Create(maxTexSize, iData->iBitmap->DisplayMode());
CleanupStack::PushL(dest);
AlfUtil::ScaleFbsBitmapL(*iData->iBitmap, *dest);
CleanupStack::Pop(); // dest
delete iData->iBitmap;
iData->iBitmap = dest;
if(aEntry.iHasAlpha)
{
// Scale the alpha as well.
dest = new (ELeave) CFbsBitmap();
dest->Create(maxTexSize, iData->iMaskBitmap->DisplayMode());
CleanupStack::PushL(dest);
AlfUtil::ScaleFbsBitmapL(*iData->iMaskBitmap, *dest);
CleanupStack::Pop(); // dest
delete iData->iMaskBitmap;
iData->iMaskBitmap = dest;
}
}
TInt bitmapHandle = 0;
TInt maskHandle = 0;
if (iData->iBitmap)
{
bitmapHandle = iData->iBitmap->Handle();
}
if (iData->iMaskBitmap && aEntry.iHasAlpha)
{
maskHandle = iData->iMaskBitmap->Handle();
}
TInt handle = iData->iEnv->Client().TextureLoadL( aEntry.iLoading.iTexture->Id(),
bitmapHandle,
maskHandle,
aEntry.iLoading.iTexture->Flags(),
iData->iManagerId.iUid);
aEntry.iLoading.iTexture->SetServerHandle(handle);
if (iData->iBitmap)
aEntry.iLoading.iTexture->SetSize(iData->iBitmap->SizeInPixels());
// Notify the observers of loaded texture
NotifyTextureLoaded(*aEntry.iLoading.iTexture, aEntry.iLoading.iId, KErrNone);
// Resize bitmaps to save memory
iData->iBitmap->Reset();
iData->iMaskBitmap->Reset();
iData->iBitmap->Create(
TSize(KAlfDefaultSizeDimension, KAlfDefaultSizeDimension), EColor64K);
iData->iMaskBitmap->Create(
TSize(KAlfDefaultSizeDimension, KAlfDefaultSizeDimension), EGray256);
// DEBUG
if (iData->iTextureAutoCounterEnabled)
{
TBuf<256> numBuf;
numBuf.FillZ();
numBuf.Append(_L("Reloads:"));
numBuf.AppendNum(iData->iTextureAutoReloadCounter);
numBuf.Append(_L(" - Recreates:"));
numBuf.AppendNum(iData->iTextureAutoRecreateCounter);
User::InfoPrint(numBuf);
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::NotifyStateChange() const
{
__ALFLOGSTRING( "CAlfTextureManager::NotifyStateChange" )
RPointerArray<MAlfTextureManagerStateChangedObserver>& observers =
(iData->iStateObserverQueue);
TInt count = observers.Count();
for(TInt i = 0; i < count; i++)
{
observers[i]->TextureManagerStateChanged(*this);
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::NotifyTextureLoaded(CAlfTexture& aTexture,
TInt aTextureId,
TInt aErrorCode) const
{
// NOTE: Commented out because this will prevent alflogging (aTexture.FileName() = NULL => crash)
// __ALFLOGSTRING3( "CAlfTextureManager::NotifyTextureLoaded -- filename: %S, textureId: %d, error: %d",
// aTexture.FileName(), aTextureId, aErrorCode )
RPointerArray<MAlfTextureLoadingCompletedObserver>& observers =
(iData->iLoadObserverQueue);
TInt count = observers.Count();
for(TInt i = 0; i < count; i++)
{
observers[i]->TextureLoadingCompleted(aTexture, aTextureId,
aErrorCode);
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
EXPORT_C void CAlfTextureManager::AddLoadObserverL(
MAlfTextureLoadingCompletedObserver* aObserver)
{
iData->iLoadObserverQueue.Append(aObserver);
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
EXPORT_C void CAlfTextureManager::RemoveLoadObserver(
MAlfTextureLoadingCompletedObserver* aObserver)
{
RPointerArray<MAlfTextureLoadingCompletedObserver>& observers =
(iData->iLoadObserverQueue);
TInt count = observers.Count();
for(TInt i = 0; i < count; i++)
{
if (observers[i] == aObserver)
{
observers.Remove(i);
observers.Compress();
break;
}
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TUid CAlfTextureManager::ManagerUid()
{
return iData->iManagerId;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
EXPORT_C CAlfTextureProcessor& CAlfTextureManager::Processor()
{
return *iData->iProcessor;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::AppendTextureL(CAlfTexture* aTexture)
{
if (CheckTexture(aTexture->Id()) == KErrNotFound)
{
// Create a new texture entry
TTextureEntry entry(aTexture->Id(), aTexture);
// Add the new entry to the list of new textures
iData->iTextures.AppendL(entry);
}
else
{
User::Leave(KErrAlreadyExists);
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::RemoveTexture(CAlfTexture& aTexture)
{
// Cancel loading of the texture to be removed.
CancelLoadingOfTexture(aTexture);
RArray<TTextureEntry>& textures = (iData->iTextures);
for(TInt i = 0; i < textures.Count(); i++)
{
TTextureEntry te = textures[i];
if (&aTexture == te.iTexture)
{
te.iTexture = NULL;
textures.Remove(i);
break;
}
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TBool CAlfTextureManager::IsInLoadQueue(const CAlfTexture* texture) const
{
TBool retVal = EFalse;
RArray<TLoadQueueEntry>& loadQueue = iData->iLoadQueue;
for(TInt i = 0; i < loadQueue.Count(); i++)
{
TLoadQueueEntry loadEntry = loadQueue[i];
if (loadEntry.iLoading.iTexture == texture)
{
retVal = ETrue;
break;
}
}
return retVal;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
CAlfTextureManager::TState CAlfTextureManager::State() const
{
return iData->iState;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
EXPORT_C void CAlfTextureManager::AddStateObserverL(
MAlfTextureManagerStateChangedObserver* aObserver)
{
iData->iStateObserverQueue.Append(aObserver);
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
EXPORT_C void CAlfTextureManager::RemoveStateObserver(
MAlfTextureManagerStateChangedObserver* aObserver)
{
RPointerArray<MAlfTextureManagerStateChangedObserver>& observers =
(iData->iStateObserverQueue);
TInt count = observers.Count();
for(TInt i = 0; i < count; i++)
{
if (observers[i] == aObserver)
{
observers.Remove(i);
observers.Compress();
break;
}
}
}
EXPORT_C TBool CAlfTextureManager::IsLoaded(const CAlfTexture * texture) const
{
if(texture != NULL && texture->HasContent() && !IsInLoadQueue(texture))
{
return ETrue;
}
return EFalse;
}
EXPORT_C TBool CAlfTextureManager::IsLoaded(const TDesC& aImageName) const
{
TFileName fileName = *iData->iImagePath;
fileName.Append(aImageName);
TInt index = CheckTexture(fileName);
if(index == KErrNotFound)
{
return EFalse;
}
return IsLoaded(iData->iTextures[index].iTexture);
}
EXPORT_C TInt CAlfTextureManager::TextureId(const TDesC& aImageName) const
{
TFileName fileName = *iData->iImagePath;
fileName.Append(aImageName);
TInt index = CheckTexture(fileName);
if(index == KErrNotFound)
{
return KErrNotFound;
}
return iData->iTextures[index].iId;
}
EXPORT_C TBool CAlfTextureManager::IsLoaded(TInt aId) const
{
ASSERT(aId!=0);
TInt index = CheckTexture(aId);
if(index == KErrNotFound)
{
return EFalse;
}
return IsLoaded(iData->iTextures[index].iTexture);
}
// ---------------------------------------------------------------------------
// Release all textures with given priority level (or above)
// ---------------------------------------------------------------------------
//
TBool CAlfTextureManager::Release( TInt aReleasePriorityLevel )
{
TBool allReleased = ETrue;
RArray<TTextureEntry>& textures = (iData->iTextures);
for(TInt i = 0; i < textures.Count(); i++)
{
if (textures[i].iTexture->Id())
{
if ( textures[i].iTexture->Priority() < aReleasePriorityLevel )
{
allReleased = EFalse;
}
else
{
if (!textures[i].iTexture->IsAnimated())
{
ReleaseEntry(textures[i]);
}
else
{
textures[i].iTexture->StopAnimation();
}
}
}
}
return allReleased;
}
// ---------------------------------------------------------------------------
// Release a specific entry
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::ReleaseEntry(const TTextureEntry& aEntry)
{
// Id texture has content, it must be released here using unload,
// otherwise we can just notify serverside.
if (aEntry.iTexture->HasContent())
{
UnloadTexture(aEntry.iTexture->Id());
}
else
{
iData->iEnv->Client().TextureRelease(aEntry.iTexture->Id(),
iData->iManagerId.iUid);
}
TInt releaseFlags = aEntry.iTexture->ReleaseFlags();
releaseFlags |= CAlfTexture::EReleaseFromEnv;
aEntry.iTexture->SetReleaseFlags(releaseFlags);
}
// ---------------------------------------------------------------------------
// Restore all textures with given priority level (or lover)
// ---------------------------------------------------------------------------
//
TBool CAlfTextureManager::RestoreL( TInt aRestorePriorityLevel )
{
TBool allRestored = ETrue;
RArray<TTextureEntry>& textures = (iData->iTextures);
for(TInt i = 0; i < textures.Count(); i++)
{
if ( textures[i].iTexture->Priority() <= aRestorePriorityLevel )
{
if (!textures[i].iTexture->IsAnimated())
{
RestoreEntryL(textures[i]);
}
else
{
textures[i].iTexture->StartAnimation();
}
}
else
{
allRestored = EFalse;
}
}
return allRestored;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::RestoreEntryL(const TTextureEntry& aEntry)
{
// Id texture has no content, it must be restored here using create/load
// otherwise we can just notify serverside.
if (!aEntry.iTexture->HasContent())
{
// Clear release flags
TInt releaseFlags = aEntry.iTexture->ReleaseFlags();
releaseFlags &= ~CAlfTexture::EReleaseFromEnv;
releaseFlags &= ~CAlfTexture::EReleaseFromUnload;
aEntry.iTexture->SetReleaseFlags(releaseFlags);
// If there are other release flags, then do not restore.
if (!releaseFlags)
{
// check for provider-based restore
if (aEntry.iTexture->BitmapProvider() != NULL)
{
CreateTextureL(aEntry.iTexture->Id(),
aEntry.iTexture->BitmapProvider(),
aEntry.iTexture->Flags());
}
// check for file-based restore
else if (aEntry.iTexture->FileName() != NULL)
{
LoadTextureL(aEntry.iTexture->FileName()->Des(),
aEntry.iTexture->MaxTextureSize(),
aEntry.iTexture->Flags(),
aEntry.iTexture->Id());
}
else
{
// for PC lint
}
}
}
else
{
iData->iEnv->Client().TextureRestore(aEntry.iTexture->Id(),
iData->iManagerId.iUid);
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::CancelLoadingOfTexture(CAlfTexture& aTexture)
{
RArray<TLoadQueueEntry>& loadQueue = iData->iLoadQueue;
for(TInt i = 0; i < loadQueue.Count(); i++)
{
if(loadQueue[i].iLoading.iTexture == &aTexture)
{
// Texture found from the load queue.
if(i == 0 && iData->iState == ELoading)
{
// Texture is currently loading
Cancel();
PopLoadedQueueEntry();
StartLoading();
}
else
{
// Delete the decoder and remove entry.
delete loadQueue[i].iDecoder;
loadQueue.Remove(i);
}
break;
}
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TInt CAlfTextureManager::GenerateTextureId()
{
TBool done = EFalse;
TInt start = iData->iAutoGeneratedTextureId;
while (!done)
{
if(iData->iAutoGeneratedTextureId == iData->iHighestAutoGeneratedTextureId)
{
iData->iAutoGeneratedTextureId = iData->iLowestAutoGeneratedTextureId;
}
else
{
iData->iAutoGeneratedTextureId++;
}
if (CheckTexture(iData->iAutoGeneratedTextureId) == KErrNotFound)
{
done = ETrue;
}
if (iData->iAutoGeneratedTextureId == start)
{
// Error! Free id was not found, already existing id will be used.
break;
}
}
return iData->iAutoGeneratedTextureId;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
EXPORT_C void CAlfTextureManager::SetAutomaticTextureIdRange(TInt aLow, TInt aHigh)
{
if (aLow < aHigh)
{
iData->iAutoGeneratedTextureId = aLow;
iData->iLowestAutoGeneratedTextureId = aLow;
iData->iHighestAutoGeneratedTextureId = aHigh;
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::NotifySkinChangedL()
{
__ALFLOGSTRING( "CAlfTextureManager::NotifySkinChangedL" )
RArray<TTextureEntry>& textures = (iData->iTextures);
for(TInt i = 0; i < textures.Count(); i++)
{
if (textures[i].iTexture->Id() &&
textures[i].iTexture->HasContent() &&
(textures[i].iTexture->Flags() & EAlfTextureFlagSkinContent))
{
iData->iEnv->Client().TextureNotifySkinChanged(textures[i].iTexture->Id(),
iData->iManagerId.iUid);
ReleaseEntry(textures[i]);
RestoreEntryL(textures[i]);
}
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TBool CAlfTextureManager::IsShared()
{
return (iData->iManagerId != TUid::Uid(0));
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::ReportTextureInfoL(
TInt aTextureId, const TSize& aTextureRect )
{
__ALFLOGSTRING1( "CAlfTextureManager::ReportTextureInfo %d", aTextureId )
__ALFLOGSTRING2( "texture size = (%d, %d)", aTextureRect.iWidth, aTextureRect.iHeight )
TBool accepted = EFalse;
CAlfTexture* texture = TextureL(aTextureId);
RPointerArray<MAlfTextureAutoSizeObserver>& observers =
(iData->iAutoSizeObserverQueue);
TInt count = observers.Count();
for(TInt i = 0; i < count; i++)
{
accepted |= observers[i]->PreferredSizeChanged(*texture, aTextureRect);
}
// File based textures are updated automatically without observer acceptance
if (texture->FileName())
{
// Update new max size, but leave undefined (zero) values untouched.
TSize maxTextureSize = texture->MaxTextureSize();
TSize oldMaxTextureSize = maxTextureSize;
if (maxTextureSize.iWidth != 0 && maxTextureSize.iHeight == 0)
{
maxTextureSize.iWidth = aTextureRect.iWidth;
}
else if (maxTextureSize.iHeight != 0 && maxTextureSize.iWidth == 0)
{
maxTextureSize.iHeight = aTextureRect.iHeight;
}
else
{
maxTextureSize = aTextureRect;
}
texture->SetMaxTextureSize(maxTextureSize);
if (!texture->ReleaseFlags() && (oldMaxTextureSize != maxTextureSize))
{
// Update if texture is not released.
UpdateTextureL(aTextureId, aTextureRect);
}
}
else
{
if (accepted && !texture->ReleaseFlags())
{
// If we did notify someone who accepted it, we assume it may now be able to
// provide new size texture. If it is released it should get updated
// automatically to new size when restore happens.
UpdateTextureL(aTextureId, aTextureRect);
}
else
{
// not accepted by any of observers, no use to update then.
}
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
EXPORT_C void CAlfTextureManager::AddAutoSizeObserverL(MAlfTextureAutoSizeObserver* aObserver)
{
iData->iAutoSizeObserverQueue.Append(aObserver);
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
EXPORT_C void CAlfTextureManager::RemoveAutoSizeObserver(MAlfTextureAutoSizeObserver* aObserver)
{
RPointerArray<MAlfTextureAutoSizeObserver>& observers =
(iData->iAutoSizeObserverQueue);
TInt count = observers.Count();
for(TInt i = 0; i < count; i++)
{
if (observers[i] == aObserver)
{
observers.Remove(i);
observers.Compress();
break;
}
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::UpdateTextureL(TInt aId, TSize /*aSize*/)
{
RArray<TTextureEntry>& textures = (iData->iTextures);
for(TInt i = 0; i < textures.Count(); i++)
{
TTextureEntry te = textures[i];
if (te.iTexture && te.iTexture->Id() == aId)
{
if (te.iTexture->BitmapProvider() != NULL)
{
UpdateTextureFromBitmapL(aId);
break;
}
else if (te.iTexture->FileName() != NULL)
{
UpdateTextureFromFileL(aId);
break;
}
else
{
// for PC lint
break;
}
}
}
}
void CAlfTextureManager::ReloadTextureL(const TDesC& aImageName,
TSize aTextureMaxSize,
TAlfTextureFlags /*aFlags*/,
TInt aId)
{
if (aId == KAlfAutoGeneratedTextureId)
{
aId = GenerateTextureId();
}
CAlfTexture* tex = NULL;
TFileName fileName;
// Texture must exist.
tex = TextureL(aId);
// 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
// there's and nonzero id has been passed, we
// can assume that there's a predefined name available
RArray<TTextureEntry>& textures = (iData->iTextures);
RArray<TLoadQueueEntry>& loadqueue = (iData->iLoadQueue);
if((aImageName.Length() == 0) && (aId != 0))
{
// search for a texture filename based on the id.
TInt index = CheckTexture(aId);
if(index >=0)
{
tex = textures[index].iTexture;
fileName = *tex->FileName();
}
else
{
User::Leave(KErrNotFound);
}
}
// return if already in the load queue ??
if (IsInLoadQueue(tex))
{
return;
}
// replace filename
// File names are relative to the image path.
tex->SetFileNameL(fileName);
TSize maxTextureSize = tex->MaxTextureSize();
// Update new max size, but leave undefined (zero) values untouched
if (maxTextureSize.iWidth != 0 && maxTextureSize.iHeight == 0)
{
maxTextureSize.iWidth = aTextureMaxSize.iWidth;
}
else if (maxTextureSize.iHeight != 0 && maxTextureSize.iWidth == 0)
{
maxTextureSize.iHeight = aTextureMaxSize.iHeight;
}
else
{
maxTextureSize = aTextureMaxSize;
}
tex->SetMaxTextureSize(maxTextureSize);
// Prepare for loading by creating a load queue entry.
TTextureEntry entry;
entry.iTexture = tex;
entry.iId = aId;
TLoadQueueEntry loadqentry;
loadqentry.iUnloaded = EFalse;
loadqentry.iLoading = entry;
loadqentry.iDecoder = NULL;
// Textures are loaded one at a time, in the order they were requested.
loadqueue.AppendL(loadqentry);
// DEBUG
if (iData->iTextureAutoCounterEnabled)
{
iData->iTextureAutoReloadCounter++;
}
// Start the texture load active object if we're not loading
if(iData->iState == EIdle)
{
// Start loading images..
StartLoading();
// Notify observers.
NotifyStateChange();
}
}
void CAlfTextureManager::RecreateTextureL(TInt aId,
MAlfBitmapProvider* aBitmapProvider,
TAlfTextureFlags aFlags)
{
CAlfTexture* tex = NULL;
if (aId == KAlfAutoGeneratedTextureId)
{
User::Leave(KErrArgument); // texture must already exist !
}
CFbsBitmap* bitmap = NULL;
CFbsBitmap* maskBitmap = NULL;
// Provide an already created texture if such exists.
TRAPD(err, tex = TextureL(aId));
if(err != KErrNone)
{
User::Leave(KErrArgument); // texture must already exist !
}
// Call the bitmapProvider method to load the bitmaps
if (aBitmapProvider)
{
aBitmapProvider->ProvideBitmapL(aId, bitmap, maskBitmap);
}
if (!bitmap)
{
// We leave here, otherwise serverside would panic.
User::Leave(KErrArgument);
// Bitmap size is checked and handled in serverside,
// so that we can create empty textures (size = 0,0)
}
// "bitmap" pointer should be valid from now on
CleanupStack::PushL(bitmap);
TInt bitmapHandle = bitmap->Handle();
TInt maskHandle = 0;
if (maskBitmap)
{
maskHandle = maskBitmap->Handle();
CleanupStack::PushL(maskBitmap);
}
// Create CAlfTexture instance, this duplicates the bitmaps to server.
// texture already exists but it does not have content, this creates content.
iData->iEnv->Client().TextureCreateL( aId, bitmapHandle,
maskHandle, aFlags, iData->iManagerId.iUid );
tex->SetBitmapProvider(aBitmapProvider);
tex->SetSize(bitmap->SizeInPixels());
// CAlfTexture has at this point duplicated bitmaps, can be deleted here.
if (maskBitmap)
{
CleanupStack::PopAndDestroy( maskBitmap );
maskBitmap = NULL;
}
CleanupStack::PopAndDestroy( bitmap );
bitmap = NULL;
// Notify observers
NotifyTextureLoaded(*tex, aId, KErrNone);
// DEBUG
if (iData->iTextureAutoCounterEnabled)
{
iData->iTextureAutoRecreateCounter++;
TBuf<256> numBuf;
numBuf.FillZ();
numBuf.Append(_L("Reloads:"));
numBuf.AppendNum(iData->iTextureAutoReloadCounter);
numBuf.Append(_L(" - Recreates:"));
numBuf.AppendNum(iData->iTextureAutoRecreateCounter);
User::InfoPrint(numBuf);
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::IncRefcount(TInt aId)
{
// do not refcount blanktextures.
if (!aId)
{
return;
}
TInt index = CheckTexture(aId);
ASSERT(index!=KErrNotFound);
TTextureEntry& te = iData->iTextures[index];
if (te.iRefCount==-1)
{
te.iRefCount = 1;
}
else
{
te.iRefCount++;
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::DecRefcount(TInt aId)
{
// do not refcount blanktextures.
if (!aId)
{
return;
}
TInt index = CheckTexture(aId);
if (index == KErrNotFound)
{
return;
}
TTextureEntry& te = iData->iTextures[index];
if (te.iRefCount >0)
{
te.iRefCount--;
}
if (!te.iRefCount)
{
// trigger texture cleanup when
// reference count hits zero
StartGarbageCollect();
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TInt CAlfTextureManager::GarbageCollect(TAny* aPtr)
{
CAlfTextureManager* tm = ((CAlfTextureManager*)(aPtr));
RArray<TTextureEntry>& textures = tm->iData->iTextures;
// Cleanup all textures which have refcount 0
TInt count = textures.Count()-1;
for (int index = count; index >=0; index--)
{
TTextureEntry& te = textures[index];
// delete only textures that have enabled refcounting
if (te.iTexture->RefCountingEnabled() && !te.iRefCount)
{
TInt action = te.iTexture->RefCountingAction();
switch (action)
{
case CAlfTexture::ERefCountingActionUnload:
{
// Unload, but mark as released from ref counting
TInt releaseFlags = te.iTexture->ReleaseFlags();
tm->UnloadTexture(te.iId);
releaseFlags |= CAlfTexture::EReleaseFromRefCounting;
te.iTexture->SetReleaseFlags(releaseFlags);
break;
}
case CAlfTexture::ERefCountingActionDelete:
{
delete te.iTexture;
te.iTexture = NULL;
break;
}
default:
{
// Do nothing
break;
}
}
}
}
return EFalse;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::StartGarbageCollect()
{
CIdle* doombringer = iData->iDoomBringer;
// check if garbagecollecting is already in progress
// -> if so, just return
if (doombringer->IsActive())
{
return;
}
doombringer->Start(TCallBack(GarbageCollect, this));
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::RemoveFlags(TAlfTextureFlags& aFlags, TInt aFlagsToBeRemoved)
{
((TInt&)aFlags) &= ~aFlagsToBeRemoved;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CAlfTextureManager::SetFlags(TAlfTextureFlags& aFlags, TInt aFlagsToBeSet)
{
((TInt&)aFlags) |= aFlagsToBeSet;
}