diff -r 000000000000 -r 15bf7259bb7c uiacceltk/hitchcock/Client/src/alftexturemanager.cpp --- /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 +#include +#include +#include +#include + +#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 iTextures; + + /** Queue of loading tasks. */ + RArray iLoadQueue; + + /** Queue of loading observers. */ + RPointerArray iLoadObserverQueue; + + /** Queue of state observers. */ + RPointerArray 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 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& 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& 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& 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& textures = (iData->iTextures); + RArray& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& textures = (iData->iTextures); + RArray& 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& 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; + } +