--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/uiacceltk/hitchcock/Client/src/alftexturemanager.cpp Tue Feb 02 07:56:43 2010 +0200
@@ -0,0 +1,2303 @@
+/*
+* 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;
+ }
+