From 5285fb04351df1e9fc1db6da11e3b40f76b6573e Mon Sep 17 00:00:00 2001 From: Seungho Baek Date: Mon, 30 Nov 2020 14:45:41 +0900 Subject: [PATCH] Request load texture again if the observer is destroyed during loading. Change-Id: I0879a9eaa62aac8533fbc6b8d9416805ab7a0675 Signed-off-by: Seungho Baek --- dali-toolkit/internal/visuals/npatch-loader.cpp | 134 +++++++++++++-------- dali-toolkit/internal/visuals/npatch-loader.h | 50 +++++--- .../internal/visuals/npatch/npatch-visual.cpp | 20 ++- .../internal/visuals/npatch/npatch-visual.h | 7 +- 4 files changed, 135 insertions(+), 76 deletions(-) diff --git a/dali-toolkit/internal/visuals/npatch-loader.cpp b/dali-toolkit/internal/visuals/npatch-loader.cpp index 2550001..3ab8cad 100644 --- a/dali-toolkit/internal/visuals/npatch-loader.cpp +++ b/dali-toolkit/internal/visuals/npatch-loader.cpp @@ -37,7 +37,7 @@ namespace Internal namespace NPatchBuffer { -void SetLoadedNPatchData( NPatchLoader::Data* data, Devel::PixelBuffer& pixelBuffer ) +void SetLoadedNPatchData( NPatchLoader::Data* data, Devel::PixelBuffer& pixelBuffer, bool preMultiplied ) { if( data->border == Rect< int >( 0, 0, 0, 0 ) ) { @@ -66,6 +66,8 @@ void SetLoadedNPatchData( NPatchLoader::Data* data, Devel::PixelBuffer& pixelBuf data->textureSet = TextureSet::New(); data->textureSet.SetTexture( 0u, texture ); + data->preMultiplyOnLoad = preMultiplied; + data->loadCompleted = true; } @@ -88,30 +90,26 @@ NPatchLoader::~NPatchLoader() { } -std::size_t NPatchLoader::Load( TextureManager& textureManager, TextureUploadObserver* textureObserver, const std::string& url, const Rect< int >& border, bool& preMultiplyOnLoad, bool synchronousLoading ) +std::size_t NPatchLoader::Load( TextureManager& textureManager, NPatchLoadObserver* nPatchObserver, const std::string& url, const Rect< int >& border, bool& preMultiplyOnLoad, bool synchronousLoading ) { std::size_t hash = CalculateHash( url ); OwnerContainer< Data* >::SizeType index = UNINITIALIZED_ID; const OwnerContainer< Data* >::SizeType count = mCache.Count(); - int cachedIndex = -1; - Data* data; for( ; index < count; ++index ) { if( mCache[ index ]->hash == hash ) { - // hash match, check url as well in case of hash collision - if( mCache[ index ]->url == url ) + // hash match, check url and preMultiplyOnLoading as well in case of hash collision + if( mCache[ index ]->url == url && mCache[ index ]->preMultiplyOnLoad == preMultiplyOnLoad ) { // Use cached data if( mCache[ index ]->border == border ) { - if( mCache[ index ]->loadCompleted ) + if( !mCache[ index ]->loadCompleted ) { - return index + 1u; // valid indices are from 1 onwards + mCache[ index ]->observerList.PushBack( nPatchObserver ); } - mCache[ index ]->observerList.PushBack( textureObserver ); - data = mCache[ index ]; return index + 1u; // valid indices are from 1 onwards } else @@ -119,27 +117,29 @@ std::size_t NPatchLoader::Load( TextureManager& textureManager, TextureUploadObs if( mCache[ index ]->loadCompleted ) { // Same url but border is different - use the existing texture - Data* data = new Data(); - data->hash = hash; - data->url = url; - data->croppedWidth = mCache[ index ]->croppedWidth; - data->croppedHeight = mCache[ index ]->croppedHeight; + Data* newData = new Data(); + newData->hash = hash; + newData->url = url; + newData->croppedWidth = mCache[ index ]->croppedWidth; + newData->croppedHeight = mCache[ index ]->croppedHeight; - data->textureSet = mCache[ index ]->textureSet; + newData->textureSet = mCache[ index ]->textureSet; NPatchUtility::StretchRanges stretchRangesX; - stretchRangesX.PushBack( Uint16Pair( border.left, ( (data->croppedWidth >= static_cast< unsigned int >( border.right )) ? data->croppedWidth - border.right : 0 ) ) ); + stretchRangesX.PushBack( Uint16Pair( border.left, ( (newData->croppedWidth >= static_cast< unsigned int >( border.right )) ? newData->croppedWidth - border.right : 0 ) ) ); NPatchUtility::StretchRanges stretchRangesY; - stretchRangesY.PushBack( Uint16Pair( border.top, ( (data->croppedHeight >= static_cast< unsigned int >( border.bottom )) ? data->croppedHeight - border.bottom : 0 ) ) ); + stretchRangesY.PushBack( Uint16Pair( border.top, ( (newData->croppedHeight >= static_cast< unsigned int >( border.bottom )) ? newData->croppedHeight - border.bottom : 0 ) ) ); - data->stretchPixelsX = stretchRangesX; - data->stretchPixelsY = stretchRangesY; - data->border = border; + newData->stretchPixelsX = stretchRangesX; + newData->stretchPixelsY = stretchRangesY; + newData->border = border; - data->loadCompleted = mCache[ index ]->loadCompleted; + newData->preMultiplyOnLoad = preMultiplyOnLoad; - mCache.PushBack( data ); + newData->loadCompleted = mCache[ index ]->loadCompleted; + + mCache.PushBack( newData ); return mCache.Count(); // valid ids start from 1u } @@ -148,53 +148,45 @@ std::size_t NPatchLoader::Load( TextureManager& textureManager, TextureUploadObs } } - if( cachedIndex == -1 ) - { - data = new Data(); - data->loadCompleted = false; - data->hash = hash; - data->url = url; - data->border = border; - - mCache.PushBack( data ); - - cachedIndex = mCache.Count(); - } + // If this is new image loading, make new cache data + Data* data; + data = new Data(); + data->loadCompleted = false; + data->hash = hash; + data->url = url; + data->border = border; + data->preMultiplyOnLoad = preMultiplyOnLoad; + data->observerList.PushBack( nPatchObserver ); + data->textureObserver = nPatchObserver; + mCache.PushBack(data); auto preMultiplyOnLoading = preMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; + Devel::PixelBuffer pixelBuffer = textureManager.LoadPixelBuffer( url, Dali::ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, synchronousLoading, - textureObserver, true, preMultiplyOnLoading ); + nPatchObserver, true, preMultiplyOnLoading ); if( pixelBuffer ) { - NPatchBuffer::SetLoadedNPatchData( data, pixelBuffer ); preMultiplyOnLoad = ( preMultiplyOnLoading == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD ) ? true : false; + NPatchBuffer::SetLoadedNPatchData( data, pixelBuffer, preMultiplyOnLoad ); } - return cachedIndex; + return mCache.Count(); } -void NPatchLoader::SetNPatchData( bool loadSuccess, std::size_t id, Devel::PixelBuffer& pixelBuffer, const Internal::VisualUrl& url, bool preMultiplied ) +void NPatchLoader::SetNPatchData( std::size_t id, Devel::PixelBuffer& pixelBuffer, bool preMultiplied ) { Data* data; data = mCache[ id - 1u ]; - // To prevent recursion. - // data->loadCompleted will be set true in the NPatchBuffer::SetLoadedNPatchData when the first observer called this method. - if( data->loadCompleted ) - { - return; - } + NPatchBuffer::SetLoadedNPatchData( data, pixelBuffer, preMultiplied ); - NPatchBuffer::SetLoadedNPatchData( data, pixelBuffer ); - - while( data->observerList.Count() ) + for(uint32_t index = 0; index < data->observerList.Count(); ++index ) { - TextureUploadObserver* observer = data->observerList[0]; - observer->LoadComplete( loadSuccess, Devel::PixelBuffer(), url, preMultiplied ); - data->observerList.Erase( data->observerList.begin() ); + NPatchLoadObserver* observer = data->observerList[index]; + observer->NPatchLoadComplete( preMultiplied ); } } @@ -209,6 +201,46 @@ bool NPatchLoader::GetNPatchData( std::size_t id, const Data*& data ) return false; } +void NPatchLoader::Remove( std::size_t id, TextureManager& textureManager, NPatchLoadObserver* nPatchObserver, bool synchronousLoading ) +{ + Data* data; + data = mCache[ id - 1u ]; + + for(uint32_t index = 0; index < data->observerList.Count(); ++index ) + { + if(nPatchObserver == data->observerList[index]) + { + data->observerList.Erase( data->observerList.begin() + index ); + break; + } + } + + if(data->observerList.Empty()) + { + data->loadCompleted = false; + data->hash = 0u; + data->url.clear(); + data->textureObserver = nullptr; + data->textureSet.Reset(); + } + else + { + if(!data->loadCompleted && data->textureObserver == nPatchObserver) + { + data->textureObserver = nPatchObserver; + auto preMultiplyOnLoading = data->preMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD + : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; + + Devel::PixelBuffer pixelBuffer = textureManager.LoadPixelBuffer(data->url, Dali::ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, synchronousLoading, nPatchObserver, true, preMultiplyOnLoading); + + if(pixelBuffer) + { + NPatchBuffer::SetLoadedNPatchData(data, pixelBuffer, (preMultiplyOnLoading == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD) ? true : false); + } + } + } +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/visuals/npatch-loader.h b/dali-toolkit/internal/visuals/npatch-loader.h index a3aa464..51f2482 100644 --- a/dali-toolkit/internal/visuals/npatch-loader.h +++ b/dali-toolkit/internal/visuals/npatch-loader.h @@ -48,6 +48,18 @@ namespace Internal class NPatchLoader { public: + /** + * Observer class to inform the npatch image is loaded. + */ + class NPatchLoadObserver: public Dali::Toolkit::TextureUploadObserver + { + public: + /** + * Informs observer when the npatch image is loaded. + * @param[in] preMultiplied True if the image had pre-multiplied alpha applied + */ + virtual void NPatchLoadComplete ( bool preMultiplied ) = 0; + }; enum { @@ -69,19 +81,21 @@ public: ~Data(); - using ObserverListType = Dali::Vector< TextureUploadObserver* >; - - ObserverListType observerList; ///< Container used to store all observer clients of this Texture - std::string url; ///< Url of the N-Patch - TextureSet textureSet; ///< Texture containing the cropped image - NPatchUtility::StretchRanges stretchPixelsX; ///< X stretch pixels - NPatchUtility::StretchRanges stretchPixelsY; ///< Y stretch pixels - std::size_t hash; ///< Hash code for the Url - uint32_t croppedWidth; ///< Width of the cropped middle part of N-patch - uint32_t croppedHeight; ///< Height of the cropped middle part of N-patch - Rect< int > border; ///< The size of the border - bool loadCompleted; ///< True if the data loading is completed - void* renderingMap; ///< NPatch rendering data + using ObserverListType = Dali::Vector< NPatchLoadObserver* >; + + TextureUploadObserver* textureObserver; ///< TextureUploadObserver that requests to load texture. + ObserverListType observerList; ///< Container used to store all observer clients of this Texture + std::string url; ///< Url of the N-Patch + TextureSet textureSet; ///< Texture containing the cropped image + NPatchUtility::StretchRanges stretchPixelsX; ///< X stretch pixels + NPatchUtility::StretchRanges stretchPixelsY; ///< Y stretch pixels + std::size_t hash; ///< Hash code for the Url + uint32_t croppedWidth; ///< Width of the cropped middle part of N-patch + uint32_t croppedHeight; ///< Height of the cropped middle part of N-patch + Rect< int > border; ///< The size of the border + bool preMultiplyOnLoad; ///< Whether to multiply alpha into color channels on load + bool loadCompleted; ///< True if the data loading is completed + void* renderingMap; ///< NPatch rendering data }; public: @@ -100,7 +114,7 @@ public: * @brief Retrieve a texture matching the n-patch url. * * @param [in] textureManager that will be used to loading image - * @param [in] textureObserver The NPatchVisual that requested loading. + * @param [in] nPatchObserver The NPatchVisual that requested loading. * @param [in] url to retrieve * @param [in] border The border size of the image * @param [in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the @@ -108,18 +122,16 @@ public: * @param [in] synchronousLoading True if the image will be loaded in synchronous time. * @return id of the texture. */ - std::size_t Load( TextureManager& textureManager, TextureUploadObserver* textureObserver, const std::string& url, const Rect< int >& border, bool& preMultiplyOnLoad, bool synchronousLoading ); + std::size_t Load( TextureManager& textureManager, NPatchLoadObserver* nPatchObserver, const std::string& url, const Rect< int >& border, bool& preMultiplyOnLoad, bool synchronousLoading ); /** * @brief Set loaded PixelBuffer and its information * - * @param [in] loadSuccess True if the texture load was successful (i.e. the resource is available). If false, then the resource failed to load. * @param [in] id cache data id * @param [in] pixelBuffer of loaded image - * @param [in] url The url address of the loaded image. * @param [in] preMultiplied True if the image had pre-multiplied alpha applied */ - void SetNPatchData( bool loadSuccess, std::size_t id, Devel::PixelBuffer& pixelBuffer, const Internal::VisualUrl& url, bool preMultiplied ); + void SetNPatchData( std::size_t id, Devel::PixelBuffer& pixelBuffer, bool preMultiplied ); /** * @brief Retrieve N patch data matching to an id @@ -129,6 +141,8 @@ public: */ bool GetNPatchData( std::size_t id, const Data*& data ); + void Remove( std::size_t id, TextureManager& textureManager, NPatchLoadObserver* nPatchObserver, bool synchronousLoading ); + protected: /** diff --git a/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp b/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp index 5c03ac2..6823cb8 100644 --- a/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp +++ b/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp @@ -476,6 +476,10 @@ NPatchVisual::NPatchVisual( VisualFactoryCache& factoryCache ) NPatchVisual::~NPatchVisual() { + TextureManager& textureManager = mFactoryCache.GetTextureManager(); + bool synchronousLoading = mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; + if(mId != NPatchLoader::UNINITIALIZED_ID) + mLoader.Remove(mId, textureManager, this, synchronousLoading); } Geometry NPatchVisual::CreateGeometry() @@ -877,18 +881,22 @@ void NPatchVisual::LoadComplete( bool loadSuccess, Devel::PixelBuffer pixelBuffe if( loadSuccess ) { loadedPixelBuffer = pixelBuffer; - EnablePreMultipliedAlpha( preMultiplied ); } else { loadedPixelBuffer = LoadImageFromFile( mFactoryCache.GetTextureManager().GetBrokenImageUrl() ); } - mLoader.SetNPatchData( loadSuccess, mId, loadedPixelBuffer, url, preMultiplied ); + mLoader.SetNPatchData( mId, loadedPixelBuffer, preMultiplied ); + } +} - if( mAuxiliaryPixelBuffer || !mAuxiliaryUrl.IsValid() ) - { - SetResource(); - } +void NPatchVisual::NPatchLoadComplete( bool preMultiplied ) +{ + EnablePreMultipliedAlpha( preMultiplied ); + + if( mAuxiliaryPixelBuffer || !mAuxiliaryUrl.IsValid() ) + { + SetResource(); } } diff --git a/dali-toolkit/internal/visuals/npatch/npatch-visual.h b/dali-toolkit/internal/visuals/npatch/npatch-visual.h index 41252f6..835f724 100644 --- a/dali-toolkit/internal/visuals/npatch/npatch-visual.h +++ b/dali-toolkit/internal/visuals/npatch/npatch-visual.h @@ -56,7 +56,7 @@ typedef IntrusivePtr< NPatchVisual > NPatchVisualPtr; * | auxiliaryImage | STRING | * | auxiliaryImageAlpha | FLOAT | */ -class NPatchVisual: public Visual::Base, public TextureUploadObserver +class NPatchVisual: public Visual::Base, public NPatchLoader::NPatchLoadObserver { public: @@ -221,6 +221,11 @@ private: */ void LoadComplete( bool loadSuccess, Devel::PixelBuffer pixelBuffer, const VisualUrl& url, bool preMultiplied ) override; + /** + * @copydoc NPatchLoader::NPatchLoadObserver::NPatchLoadComplete + */ + void NPatchLoadComplete( bool preMultiplied ) override; + private: WeakHandle mPlacementActor; ///< Weakhandle to contain Actor during texture loading -- 2.7.4