From e9ce8b35ce64531e5c6c6214527a5bf9b9747a36 Mon Sep 17 00:00:00 2001 From: Seungho Baek Date: Mon, 30 Nov 2020 14:45:41 +0900 Subject: [PATCH 1/1] Make NPatchData receive LoadComplete call from TextureManager. - If an NPatchVisual is destroyed before it receives LoadComplete, the loading process of the npatch image is never completed. - At that time, because the cache data is already created, every request of the image after that is ignored. - In this patch, NPatchData is separated from NpatchLoader and NPatchData request npatch loading to Texture Manager instead of NPatchVisual as a representative. - After the loading is completed, NPatchData receives LoadComplete call and makes textureSet. - And, The NpatchData sends UploadComplete call to the each NPatchVisuals those originally request it. + Additionally, this patch includes an method to remove unused cached data. Change-Id: I0879a9eaa62aac8533fbc6b8d9416805ab7a0675 Signed-off-by: Seungho Baek --- .../addons/test-rendering-addon.cpp | 2 +- .../src/dali-toolkit/utc-Dali-VisualFactory.cpp | 78 +++++- .../controls/control/control-data-impl.cpp | 99 ++++--- dali-toolkit/internal/file.list | 1 + dali-toolkit/internal/visuals/npatch-data.cpp | 251 +++++++++++++++++ dali-toolkit/internal/visuals/npatch-data.h | 303 +++++++++++++++++++++ dali-toolkit/internal/visuals/npatch-loader.cpp | 183 ++++++------- dali-toolkit/internal/visuals/npatch-loader.h | 66 ++--- .../internal/visuals/npatch/npatch-visual.cpp | 142 +++++----- .../internal/visuals/npatch/npatch-visual.h | 23 +- .../internal/visuals/texture-manager-impl.cpp | 6 - .../internal/visuals/texture-manager-impl.h | 6 - 12 files changed, 871 insertions(+), 289 deletions(-) create mode 100644 dali-toolkit/internal/visuals/npatch-data.cpp create mode 100644 dali-toolkit/internal/visuals/npatch-data.h diff --git a/automated-tests/src/dali-toolkit-internal/addons/test-rendering-addon.cpp b/automated-tests/src/dali-toolkit-internal/addons/test-rendering-addon.cpp index 6756093..a94f92b 100644 --- a/automated-tests/src/dali-toolkit-internal/addons/test-rendering-addon.cpp +++ b/automated-tests/src/dali-toolkit-internal/addons/test-rendering-addon.cpp @@ -76,7 +76,7 @@ static Geometry CreateGeometryMapInternal(const void* opacityMap, return Dali::Geometry::New(); } -static void* NPatchBuildInternal(const Devel::PixelBuffer& pixelBuffer, Toolkit::Internal::NPatchLoader::Data* data ) +static void* NPatchBuildInternal(const Devel::PixelBuffer& pixelBuffer, Toolkit::Internal::NPatchData* data ) { gCallStack.emplace_back( "BuildNPatch" ); fprintf(stderr, "AddOn::NPatchBuild()\n"); diff --git a/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp b/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp index db708c1..929825c 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp @@ -771,9 +771,6 @@ int UtcDaliVisualFactoryGetNPatchVisual3(void) DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); - application.GetScene().Remove( actor ); - DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); - Vector2 naturalSize( 0.0f, 0.0f ); visual.GetNaturalSize( naturalSize ); DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth() - 2.0f, imageSize.GetHeight() - 2.0f ), TEST_LOCATION ); @@ -984,6 +981,79 @@ int UtcDaliVisualFactoryGetNPatchVisual7(void) END_TEST; } +int UtcDaliVisualFactoryGetNPatchVisual8(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcDaliVisualFactoryGetNPatchVisual8: Add 9-patch visual on stage, instantly remove it and add new 9-patch visual with same propertyMap" ); + + VisualFactory factory = VisualFactory::Get(); + DALI_TEST_CHECK( factory ); + + // Get actual size of test image + ImageDimensions imageSize = Dali::GetClosestImageSize( TEST_9_PATCH_FILE_NAME ); + + Property::Map propertyMap; + propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH ); + propertyMap.Insert( ImageVisual::Property::URL, TEST_9_PATCH_FILE_NAME ); + propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, false ); + { + Visual::Base visual = factory.CreateVisual( propertyMap ); + DALI_TEST_CHECK( visual ); + + Vector2 naturalSize( 0.0f, 0.0f ); + visual.GetNaturalSize( naturalSize ); + DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth(), imageSize.GetHeight() ), TEST_LOCATION ); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + DummyControl actor = DummyControl::New(true); + + DummyControlImpl& dummyImpl = static_cast(actor.GetImplementation()); + dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual ); + + actor.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) ); + DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION ); + + application.GetScene().Add( actor ); + actor.Unparent(); + + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(); + + visual = factory.CreateVisual( propertyMap ); + DALI_TEST_CHECK( visual ); + + visual.GetNaturalSize( naturalSize ); + DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth(), imageSize.GetHeight() ), TEST_LOCATION ); + + actor = DummyControl::New(true); + + DummyControlImpl& dummyImpl2 = static_cast(actor.GetImplementation()); + dummyImpl2.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual ); + + actor.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) ); + DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION ); + + application.GetScene().Add( actor ); + + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger(1 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(); + + Renderer renderer = actor.GetRendererAt( 0 ); + auto textures = renderer.GetTextures(); + + DALI_TEST_EQUALS( textures.GetTextureCount(), 1, TEST_LOCATION ); + } + + END_TEST; +} + int UtcDaliNPatchVisualAuxiliaryImage01(void) { ToolkitTestApplication application; @@ -1061,7 +1131,7 @@ int UtcDaliNPatchVisualAuxiliaryImage02(void) Renderer renderer2 = imageView2.GetRendererAt( 0 ); auto textureSet2 = renderer2.GetTextures(); - DALI_TEST_EQUALS( textureSet1 == textureSet2, true, TEST_LOCATION ); + DALI_TEST_EQUALS( textureSet1 != textureSet2, true, TEST_LOCATION ); END_TEST; } diff --git a/dali-toolkit/internal/controls/control/control-data-impl.cpp b/dali-toolkit/internal/controls/control/control-data-impl.cpp index 2c9dca5..4e12efb 100755 --- a/dali-toolkit/internal/controls/control/control-data-impl.cpp +++ b/dali-toolkit/internal/controls/control/control-data-impl.cpp @@ -104,25 +104,30 @@ void Remove( DictionaryKeys& keys, const std::string& name ) } } -Toolkit::Visual::Type GetVisualTypeFromMap( const Property::Map& map ) +/** + * Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter + */ +bool FindVisual( Property::Index targetIndex, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter ) { - Property::Value* typeValue = map.Find( Toolkit::Visual::Property::TYPE, VISUAL_TYPE ); - Toolkit::Visual::Type type = Toolkit::Visual::IMAGE; - if( typeValue ) + for ( iter = visuals.Begin(); iter != visuals.End(); iter++ ) { - Scripting::GetEnumerationProperty( *typeValue, VISUAL_TYPE_TABLE, VISUAL_TYPE_TABLE_COUNT, type ); + if ( (*iter)->index == targetIndex ) + { + return true; + } } - return type; + return false; } /** * Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter */ -bool FindVisual( Property::Index targetIndex, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter ) +bool FindVisual( std::string visualName, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter ) { for ( iter = visuals.Begin(); iter != visuals.End(); iter++ ) { - if ( (*iter)->index == targetIndex ) + Toolkit::Visual::Base visual = (*iter)->visual; + if( visual && visual.GetName() == visualName ) { return true; } @@ -1558,59 +1563,47 @@ void Control::Impl::RecreateChangedVisuals( Dictionary& stateVisu const std::string& visualName = (*iter).key; const Property::Map& toMap = (*iter).entry; - // is it a candidate for re-creation? - bool recreate = false; - - Toolkit::Visual::Base visual = GetVisualByName( mVisuals, visualName ); - if( visual ) + Actor self = mControlImpl.Self(); + RegisteredVisualContainer::Iterator registeredVisualsiter; + // Check if visual (visualName) is already registered, this is the current visual. + if(FindVisual(visualName, mVisuals, registeredVisualsiter)) { - Property::Map fromMap; - visual.CreatePropertyMap( fromMap ); - - Toolkit::Visual::Type fromType = GetVisualTypeFromMap( fromMap ); - Toolkit::Visual::Type toType = GetVisualTypeFromMap( toMap ); - - if( fromType != toType ) - { - recreate = true; - } - else + Toolkit::Visual::Base& visual = (*registeredVisualsiter)->visual; + if(visual) { - if( fromType == Toolkit::Visual::IMAGE || fromType == Toolkit::Visual::N_PATCH - || fromType == Toolkit::Visual::SVG || fromType == Toolkit::Visual::ANIMATED_IMAGE ) - { - Property::Value* fromUrl = fromMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME ); - Property::Value* toUrl = toMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME ); + // No longer required to know if the replaced visual's resources are ready + StopObservingVisual(visual); - if( fromUrl && toUrl ) + // If control staged then visuals will be swapped once ready + if(self.GetProperty(Actor::Property::CONNECTED_TO_SCENE)) + { + // Check if visual is currently in the process of being replaced ( is in removal container ) + RegisteredVisualContainer::Iterator visualQueuedForRemoval; + if(FindVisual(visualName, mRemoveVisuals, visualQueuedForRemoval)) { - std::string fromUrlString; - std::string toUrlString; - fromUrl->Get(fromUrlString); - toUrl->Get(toUrlString); - - if( fromUrlString != toUrlString ) - { - recreate = true; - } + // Visual with same visual name is already in removal container so current visual pending + // Only the the last requested visual will be displayed so remove current visual which is staged but not ready. + Toolkit::GetImplementation(visual).SetOffScene(self); + (*registeredVisualsiter)->visual.Reset(); + mVisuals.Erase(registeredVisualsiter); + } + else + { + // current visual not already in removal container so add now. + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %s \n", visualName.c_str()); + MoveVisual(registeredVisualsiter, mVisuals, mRemoveVisuals); } } + else + { + // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later. + (*registeredVisualsiter)->visual.Reset(); + mVisuals.Erase(registeredVisualsiter); + } } - const Property::Map* instancedMap = instancedProperties.FindConst( visualName ); - if( recreate || instancedMap ) - { - RemoveVisual( mVisuals, visualName ); - Style::ApplyVisual( handle, visualName, toMap, instancedMap ); - } - else - { - // @todo check to see if we can apply toMap without recreating the visual - // e.g. by setting only animatable properties - // For now, recreate all visuals, but merge in instance data. - RemoveVisual( mVisuals, visualName ); - Style::ApplyVisual( handle, visualName, toMap, instancedMap ); - } + const Property::Map* instancedMap = instancedProperties.FindConst(visualName); + Style::ApplyVisual(handle, visualName, toMap, instancedMap); } } } diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index 29ec224..8cc93bc 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -34,6 +34,7 @@ SET( toolkit_src_files ${toolkit_src_dir}/visuals/image-atlas-manager.cpp ${toolkit_src_dir}/visuals/image/image-visual.cpp ${toolkit_src_dir}/visuals/mesh/mesh-visual.cpp + ${toolkit_src_dir}/visuals/npatch-data.cpp ${toolkit_src_dir}/visuals/npatch-loader.cpp ${toolkit_src_dir}/visuals/npatch/npatch-visual.cpp ${toolkit_src_dir}/visuals/primitive/primitive-visual.cpp diff --git a/dali-toolkit/internal/visuals/npatch-data.cpp b/dali-toolkit/internal/visuals/npatch-data.cpp new file mode 100644 index 0000000..1097395 --- /dev/null +++ b/dali-toolkit/internal/visuals/npatch-data.cpp @@ -0,0 +1,251 @@ + /* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include + +// INTERNAL HEADERS +#include + +// EXTERNAL HEADERS +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +NPatchData::NPatchData() +: mId(INVALID_NPATCH_DATA_ID), + mUrl(), + mTextureSet(), + mHash(0), + mCroppedWidth(0), + mCroppedHeight(0), + mBorder(0, 0, 0, 0), + mLoadingState(LoadingState::LOADING), + mRenderingMap{nullptr} +{ +} + +NPatchData::~NPatchData() +{ + // If there is an opacity map, it has to be destroyed using addon call + if( mRenderingMap ) + { + RenderingAddOn::Get().DestroyNPatch( mRenderingMap ); + } +} + +void NPatchData::SetId(const NPatchDataId id) +{ + mId = id; +} + +NPatchData::NPatchDataId NPatchData::GetId() const +{ + return mId; +} + +void NPatchData::AddObserver(TextureUploadObserver* textureObserver) +{ + mObserverList.PushBack( textureObserver ); +} + +void NPatchData::RemoveObserver(TextureUploadObserver* textureObserver) +{ + for(uint32_t index = 0; index < mObserverList.Count(); ++index ) + { + if(textureObserver == mObserverList[index]) + { + mObserverList.Erase( mObserverList.begin() + index ); + break; + } + } +} + +uint32_t NPatchData::GetObserverCount() const +{ + return mObserverList.Count(); +} + +void NPatchData::SetUrl(const std::string url) +{ + mUrl = url; +} + +std::string NPatchData::GetUrl() const +{ + return mUrl; +} + +void NPatchData::SetTextures(const TextureSet textureSet) +{ + mTextureSet = textureSet; +} + +TextureSet NPatchData::GetTextures() const +{ + return mTextureSet; +} + +void NPatchData::SetStretchPixelsX(const NPatchUtility::StretchRanges stretchPixelsX) +{ + mStretchPixelsX = stretchPixelsX; +} + +void NPatchData::SetStretchPixelsY(const NPatchUtility::StretchRanges stretchPixelsY) +{ + mStretchPixelsY = stretchPixelsY; +} + +NPatchUtility::StretchRanges NPatchData::GetStretchPixelsX() const +{ + return mStretchPixelsX; +} + +NPatchUtility::StretchRanges NPatchData::GetStretchPixelsY() const +{ + return mStretchPixelsY; +} + +void NPatchData::SetHash(std::size_t hash) +{ + mHash = hash; +} + +std::size_t NPatchData::GetHash() const +{ + return mHash; +} + +void NPatchData::SetCroppedWidth(uint32_t croppedWidth) +{ + mCroppedWidth = croppedWidth; +} + +void NPatchData::SetCroppedHeight(uint32_t croppedHeight) +{ + mCroppedHeight = croppedHeight; +} + +uint32_t NPatchData::GetCroppedWidth() const +{ + return mCroppedWidth; +} + +uint32_t NPatchData::GetCroppedHeight() const +{ + return mCroppedHeight; +} + +void NPatchData::SetBorder(const Rect border) +{ + mBorder = border; +} + +Rect NPatchData::GetBorder() const +{ + return mBorder; +} + +void NPatchData::SetPreMultiplyOnLoad(bool preMultiplyOnLoad) +{ + mPreMultiplyOnLoad = preMultiplyOnLoad; +} + +bool NPatchData::IsPreMultiplied() const +{ + return mPreMultiplyOnLoad; +} + +void NPatchData::SetLoadingState(const LoadingState loadingState) +{ + mLoadingState = loadingState; +} + +NPatchData::LoadingState NPatchData::GetLoadingState() const +{ + return mLoadingState; +} + +void* NPatchData::GetRenderingMap() const +{ + return mRenderingMap; +} + +void NPatchData::SetLoadedNPatchData( Devel::PixelBuffer& pixelBuffer, bool preMultiplied ) +{ + if( mBorder == Rect< int >( 0, 0, 0, 0 ) ) + { + NPatchUtility::ParseBorders( pixelBuffer, mStretchPixelsX, mStretchPixelsY ); + + // Crop the image + pixelBuffer.Crop( 1, 1, pixelBuffer.GetWidth() - 2, pixelBuffer.GetHeight() - 2 ); + } + else + { + mStretchPixelsX.PushBack( Uint16Pair( mBorder.left, ( (pixelBuffer.GetWidth() >= static_cast< unsigned int >( mBorder.right )) ? pixelBuffer.GetWidth() - mBorder.right : 0 ) ) ); + mStretchPixelsY.PushBack( Uint16Pair( mBorder.top, ( (pixelBuffer.GetHeight() >= static_cast< unsigned int >( mBorder.bottom )) ? pixelBuffer.GetHeight() - mBorder.bottom : 0 ) ) ); + } + + mCroppedWidth = pixelBuffer.GetWidth(); + mCroppedHeight = pixelBuffer.GetHeight(); + + // Create opacity map + mRenderingMap = RenderingAddOn::Get().IsValid() ? RenderingAddOn::Get().BuildNPatch(pixelBuffer, this) : nullptr; + + PixelData pixels = Devel::PixelBuffer::Convert( pixelBuffer ); // takes ownership of buffer + + Texture texture = Texture::New( TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight() ); + texture.Upload( pixels ); + + mTextureSet = TextureSet::New(); + mTextureSet.SetTexture( 0u, texture ); + + mPreMultiplyOnLoad = preMultiplied; + + mLoadingState = LoadingState::LOAD_COMPLETE; +} + +void NPatchData::LoadComplete( bool loadSuccess, Devel::PixelBuffer pixelBuffer, const VisualUrl& url, bool preMultiplied ) +{ + if(loadSuccess) + { + SetLoadedNPatchData( pixelBuffer, preMultiplied ); + } + else + { + mLoadingState = LoadingState::LOAD_FAILED; + } + + for(uint32_t index = 0; index < mObserverList.Count(); ++index) + { + TextureUploadObserver* observer = mObserverList[index]; + observer->UploadComplete(loadSuccess, TextureManager::INVALID_TEXTURE_ID, mTextureSet, false, Vector4(), preMultiplied); + } +} + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/visuals/npatch-data.h b/dali-toolkit/internal/visuals/npatch-data.h new file mode 100644 index 0000000..60e6e6b --- /dev/null +++ b/dali-toolkit/internal/visuals/npatch-data.h @@ -0,0 +1,303 @@ +#ifndef DALI_TOOLKIT_NPATCH_DATA_H +#define DALI_TOOLKIT_NPATCH_DATA_H + +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// EXTERNAL INCLUDES +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +class NPatchData : public Dali::Toolkit::TextureUploadObserver +{ +public: + typedef int32_t NPatchDataId; ///< The NPatchDataId type. This is used as a handle to refer to a particular Npatch Data. + static const int INVALID_NPATCH_DATA_ID = -1; ///< Used to represent a null TextureId or error + + /** + * @brief Loading State of the NPatch image. + */ + enum class LoadingState + { + LOADING = 0, ///< NPatch is on loading. + LOAD_COMPLETE, ///< NPatch loading is completed successfully. + LOAD_FAILED ///< NPatch loading is failed. + }; + +public: + + /** + * Constructor + */ + NPatchData(); + + /** + * Destructor, non-virtual as not a base class + */ + ~NPatchData(); + +public: + + /** + * @brief Set cache data id. + * + * @param [in] id cache data id + */ + void SetId(const NPatchDataId id); + + /** + * @brief Retrieve cache data id + * + * @return cache data id. + */ + NPatchDataId GetId() const; + + /** + * @brief Add TextureUploadObserver that uses the image of this cache data. + * + * @param [in] textureObserver the TextureUploadObserver that uses the image of this cache data. + */ + void AddObserver(TextureUploadObserver* textureObserver); + + /** + * @brief Remove TextureUploadObserver. + * + * @param [in] textureObserver the TextureUploadObserver that will be removed in this cache data. + */ + void RemoveObserver(TextureUploadObserver* textureObserver); + + /** + * @brief Retrieve the number of observer. + * + * @return Return the number of observer. + */ + uint32_t GetObserverCount() const; + + /** + * @brief Set NPatch image url. + * + * @param [in] url NPatch image url + */ + void SetUrl(const std::string url); + + /** + * @brief Retrieve the image url. + * + * @return Return the image url. + */ + std::string GetUrl() const; + + /** + * @brief Set texture set on the cache data + * + * @param [in] textureSet loaded texture set + */ + void SetTextures(const TextureSet textureSet); + + /** + * @brief Retrieve loaded texture set. + * + * @return Return loaded texture set. + */ + TextureSet GetTextures() const; + + /** + * @brief Set X directional stretchPixels + * + * @param [in] stretchPixelsX stretchPixels for X direction + */ + void SetStretchPixelsX(const NPatchUtility::StretchRanges stretchPixelsX); + + /** + * @brief Set Y directional stretchPixels + * + * @param [in] stretchPixelsY stretchPixels for Y direction + */ + void SetStretchPixelsY(const NPatchUtility::StretchRanges stretchPixelsY); + + /** + * @brief Retrieve stretchPixels for X direction. + * + * @return Return stretchPixels for X direction. + */ + NPatchUtility::StretchRanges GetStretchPixelsX() const; + + /** + * @brief Retrieve stretchPixels for Y direction. + * + * @return Return stretchPixels for Y direction. + */ + NPatchUtility::StretchRanges GetStretchPixelsY() const; + + /** + * @brief Set cache data hash. + * + * @param [in] hash cache hash + */ + void SetHash(std::size_t hash); + + /** + * @brief Retrieve hash value of the cache. + * + * @return Return hash value of the cache. + */ + std::size_t GetHash() const; + + /** + * @brief Set croppedWidth of NPatch + * + * @param [in] croppedWidth croppedWidth of NPatch + */ + void SetCroppedWidth(uint32_t croppedWidth); + + /** + * @brief Set croppedHeight of NPatch + * + * @param [in] croppedHeight croppedHeight of NPatch + */ + void SetCroppedHeight(uint32_t croppedHeight); + + /** + * @brief Retrieve croppedWidth of NPatch. + * + * @return Return croppedWidth of NPatch. + */ + uint32_t GetCroppedWidth() const; + + /** + * @brief Retrieve croppedHeight of NPatch. + * + * @return Return croppedHeight of NPatch. + */ + uint32_t GetCroppedHeight() const; + + /** + * @brief Set border of NPatch. + * + * @param [in] border border of NPatch + */ + void SetBorder(const Rect border); + + /** + * @brief Retrieve border of NPatch. + * + * @return Return border of NPatch. + */ + Rect GetBorder() const; + + /** + * @brief Set whether the loaded image is premultiplied or not + * + * @param [in] preMultiplyOnLoad whether the loaded image is premultiplied or not + */ + void SetPreMultiplyOnLoad(bool preMultiplyOnLoad); + + /** + * @brief Retrieve whether the loaded image is premultiplied or not. + * + * @return Return true if the image is premultiplied alpha. + */ + bool IsPreMultiplied() const; + + /** + * @brief Set current loading state. + * + * @param [in] loadingState current loading state + */ + void SetLoadingState(const LoadingState loadingState); + + /** + * @brief Retrieve current loading state. + * + * @return Return current loading state. + */ + LoadingState GetLoadingState() const; + + + /** + * @brief Retrieve NPatch rendering data. + * + * @return Return NPatch rendering data. + */ + void* GetRenderingMap() const; + + /** + * @brief Set loaded pixel buffer for the cache data. + * + * @param [in] pixelBuffer loaded pixel buffer. + * @param [in] preMultiplied whether the loaded image is premultiplied or not + */ + void SetLoadedNPatchData( Devel::PixelBuffer& pixelBuffer, bool preMultiplied ); + +private: + + /** + * @copydoc TextureUploadObserver::UploadCompleted + * + * To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready. + * This callback is the place to add the renderer as it would be called once the loading is finished. + */ + void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing, const Vector4& atlasRect, bool preMultiplied ) override {} + + /** + * @copydoc TextureUploadObserver::LoadComplete + * + * To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready. + * This callback is the place to add the renderer as it would be called once the loading is finished. + */ + void LoadComplete( bool loadSuccess, Devel::PixelBuffer pixelBuffer, const VisualUrl& url, bool preMultiplied ) override; + + +private: + + using ObserverListType = Dali::Vector; + + NPatchDataId mId; + ObserverListType mObserverList; ///< Container used to store all observer clients of this Texture + std::string mUrl; ///< Url of the N-Patch + TextureSet mTextureSet; ///< Texture containing the cropped image + NPatchUtility::StretchRanges mStretchPixelsX; ///< X stretch pixels + NPatchUtility::StretchRanges mStretchPixelsY; ///< Y stretch pixels + std::size_t mHash; ///< Hash code for the Url + uint32_t mCroppedWidth; ///< Width of the cropped middle part of N-patch + uint32_t mCroppedHeight; ///< Height of the cropped middle part of N-patch + Rect mBorder; ///< The size of the border + LoadingState mLoadingState; ///< True if the data loading is completed + bool mPreMultiplyOnLoad; ///< Whether to multiply alpha into color channels on load + void* mRenderingMap; ///< NPatch rendering data +}; + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_NPATCH_DATA_H diff --git a/dali-toolkit/internal/visuals/npatch-loader.cpp b/dali-toolkit/internal/visuals/npatch-loader.cpp index 2550001..f5d92ab 100644 --- a/dali-toolkit/internal/visuals/npatch-loader.cpp +++ b/dali-toolkit/internal/visuals/npatch-loader.cpp @@ -34,179 +34,160 @@ namespace Toolkit namespace Internal { -namespace NPatchBuffer +namespace { -void SetLoadedNPatchData( NPatchLoader::Data* data, Devel::PixelBuffer& pixelBuffer ) -{ - if( data->border == Rect< int >( 0, 0, 0, 0 ) ) - { - NPatchUtility::ParseBorders( pixelBuffer, data->stretchPixelsX, data->stretchPixelsY ); - - // Crop the image - pixelBuffer.Crop( 1, 1, pixelBuffer.GetWidth() - 2, pixelBuffer.GetHeight() - 2 ); - } - else - { - data->stretchPixelsX.PushBack( Uint16Pair( data->border.left, ( (pixelBuffer.GetWidth() >= static_cast< unsigned int >( data->border.right )) ? pixelBuffer.GetWidth() - data->border.right : 0 ) ) ); - data->stretchPixelsY.PushBack( Uint16Pair( data->border.top, ( (pixelBuffer.GetHeight() >= static_cast< unsigned int >( data->border.bottom )) ? pixelBuffer.GetHeight() - data->border.bottom : 0 ) ) ); - } - - data->croppedWidth = pixelBuffer.GetWidth(); - data->croppedHeight = pixelBuffer.GetHeight(); - - // Create opacity map - data->renderingMap = RenderingAddOn::Get().IsValid() ? RenderingAddOn::Get().BuildNPatch(pixelBuffer, data ) : nullptr; - - PixelData pixels = Devel::PixelBuffer::Convert( pixelBuffer ); // takes ownership of buffer - - Texture texture = Texture::New( TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight() ); - texture.Upload( pixels ); +constexpr auto INVALID_CACHE_INDEX = int32_t{-1}; ///< Invalid Cache index +constexpr auto UNINITIALIZED_ID = int32_t{0}; ///< uninitialised id, use to initialize ids - data->textureSet = TextureSet::New(); - data->textureSet.SetTexture( 0u, texture ); +} // Anonymous namespace - data->loadCompleted = true; -} - -} // namespace NPatchBuffer - -NPatchLoader::Data::~Data() +NPatchLoader::NPatchLoader() +: mCurrentNPatchDataId(0) { - // If there is an opacity map, it has to be destroyed using addon call - if( renderingMap ) - { - RenderingAddOn::Get().DestroyNPatch( renderingMap ); - } } -NPatchLoader::NPatchLoader() +NPatchLoader::~NPatchLoader() { } -NPatchLoader::~NPatchLoader() +NPatchData::NPatchDataId NPatchLoader::GenerateUniqueNPatchDataId() { + return mCurrentNPatchDataId++; } std::size_t NPatchLoader::Load( TextureManager& textureManager, TextureUploadObserver* textureObserver, 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; + OwnerContainer< NPatchData* >::SizeType index = UNINITIALIZED_ID; + const OwnerContainer< NPatchData* >::SizeType count = mCache.Count(); for( ; index < count; ++index ) { - if( mCache[ index ]->hash == hash ) + if( mCache[ index ]->GetHash() == hash ) { // hash match, check url as well in case of hash collision - if( mCache[ index ]->url == url ) + if(mCache[ index ]->GetUrl() == url) { // Use cached data - if( mCache[ index ]->border == border ) + if( mCache[ index ]->GetBorder() == border ) { - if( mCache[ index ]->loadCompleted ) + if( mCache[ index ]->GetLoadingState() == NPatchData::LoadingState::LOADING ) { - return index + 1u; // valid indices are from 1 onwards + mCache[ index ]->AddObserver( textureObserver ); } - mCache[ index ]->observerList.PushBack( textureObserver ); - data = mCache[ index ]; - return index + 1u; // valid indices are from 1 onwards + return mCache[ index ]->GetId(); // valid indices are from 1 onwards } else { - if( mCache[ index ]->loadCompleted ) + if( mCache[ index ]->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE ) { // 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; + NPatchData* newData = new NPatchData(); + newData->SetId(GenerateUniqueNPatchDataId()); + newData->SetHash(hash); + newData->SetUrl(url); + newData->SetCroppedWidth(mCache[ index ]->GetCroppedWidth()); + newData->SetCroppedHeight(mCache[ index ]->GetCroppedHeight()); - data->textureSet = mCache[ index ]->textureSet; + newData->SetTextures(mCache[ index ]->GetTextures()); 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->GetCroppedWidth() >= static_cast< unsigned int >( border.right )) ? newData->GetCroppedHeight() - 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->GetCroppedWidth() >= static_cast< unsigned int >( border.bottom )) ? newData->GetCroppedHeight() - border.bottom : 0 ) ) ); + + newData->SetStretchPixelsX(stretchRangesX); + newData->SetStretchPixelsY(stretchRangesY); + newData->SetBorder(border); - data->stretchPixelsX = stretchRangesX; - data->stretchPixelsY = stretchRangesY; - data->border = border; + newData->SetPreMultiplyOnLoad(mCache[ index ]->IsPreMultiplied()); - data->loadCompleted = mCache[ index ]->loadCompleted; + newData->SetLoadingState(NPatchData::LoadingState::LOAD_COMPLETE); + newData->AddObserver( textureObserver ); - mCache.PushBack( data ); + mCache.PushBack( newData ); - return mCache.Count(); // valid ids start from 1u + return newData->GetId(); // valid ids start from 1u } } } } } - 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 + NPatchData* data; + data = new NPatchData(); + data->SetId(GenerateUniqueNPatchDataId()); + data->SetHash(hash); + data->SetUrl(url); + data->SetBorder(border); + data->SetPreMultiplyOnLoad(preMultiplyOnLoad); + data->AddObserver(textureObserver); + 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 ); + data, true, preMultiplyOnLoading ); if( pixelBuffer ) { - NPatchBuffer::SetLoadedNPatchData( data, pixelBuffer ); preMultiplyOnLoad = ( preMultiplyOnLoading == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD ) ? true : false; + data->SetLoadedNPatchData( pixelBuffer, preMultiplyOnLoad ); } - return cachedIndex; + return data->GetId(); } -void NPatchLoader::SetNPatchData( bool loadSuccess, std::size_t id, Devel::PixelBuffer& pixelBuffer, const Internal::VisualUrl& url, bool preMultiplied ) +int32_t NPatchLoader::GetCacheIndexFromId( const NPatchData::NPatchDataId id ) { - Data* data; - data = mCache[ id - 1u ]; + const unsigned int size = mCache.Count(); - // To prevent recursion. - // data->loadCompleted will be set true in the NPatchBuffer::SetLoadedNPatchData when the first observer called this method. - if( data->loadCompleted ) + for( unsigned int i = 0; i < size; ++i ) { - return; + if( mCache[i]->GetId() == id ) + { + return i; + } } - NPatchBuffer::SetLoadedNPatchData( data, pixelBuffer ); + DALI_LOG_ERROR("Wrong NPatchDataId is used\n"); + return INVALID_CACHE_INDEX; +} - while( data->observerList.Count() ) +bool NPatchLoader::GetNPatchData( const NPatchData::NPatchDataId id, const NPatchData*& data ) +{ + int32_t cacheIndex = GetCacheIndexFromId(id); + if( cacheIndex != INVALID_CACHE_INDEX ) { - TextureUploadObserver* observer = data->observerList[0]; - observer->LoadComplete( loadSuccess, Devel::PixelBuffer(), url, preMultiplied ); - data->observerList.Erase( data->observerList.begin() ); + data = mCache[cacheIndex]; + return true; } + data = nullptr; + return false; } -bool NPatchLoader::GetNPatchData( std::size_t id, const Data*& data ) +void NPatchLoader::Remove( std::size_t id, TextureUploadObserver* textureObserver ) { - if( ( id > UNINITIALIZED_ID )&&( id <= mCache.Count() ) ) + int32_t cacheIndex = GetCacheIndexFromId(id); + if( cacheIndex == INVALID_CACHE_INDEX ) { - data = mCache[ id - 1u ]; // id's start from 1u - return true; + return; + } + + NPatchData* data; + data = mCache[cacheIndex]; + + data->RemoveObserver(textureObserver); + + if(data->GetObserverCount() == 0) + { + mCache.Erase( mCache.Begin() + cacheIndex ); } - data = NULL; - return false; } } // namespace Internal diff --git a/dali-toolkit/internal/visuals/npatch-loader.h b/dali-toolkit/internal/visuals/npatch-loader.h index a3aa464..b2b4a7c 100644 --- a/dali-toolkit/internal/visuals/npatch-loader.h +++ b/dali-toolkit/internal/visuals/npatch-loader.h @@ -24,6 +24,7 @@ #include // INTERNAL INCLUDES +#include #include #include @@ -49,43 +50,6 @@ class NPatchLoader { public: - enum - { - UNINITIALIZED_ID = 0 ///< uninitialised id, use to initialize ids - }; - - struct Data - { - Data() - : url(), - textureSet(), - hash( 0 ), - croppedWidth( 0 ), - croppedHeight( 0 ), - border( 0, 0, 0, 0 ), - loadCompleted( false ), - renderingMap{ nullptr } - {} - - ~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 - }; - -public: - /** * Constructor */ @@ -113,21 +77,35 @@ public: /** * @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 * @param [in] id of data - * @param [out] data const pointer to the data + * @param [out] data const pointer to the NPatchData * @return true if data matching to id was really found */ - bool GetNPatchData( std::size_t id, const Data*& data ); + bool GetNPatchData( const NPatchData::NPatchDataId id, const NPatchData*& data ); + + /** + * @brief Remove a texture matching id. + * Erase the observer from the observer list of cache. + * If the observer list is empty, the textureSet will be reset. + * + * @param [in] id cache data id + * @param [in] textureObserver The NPatchVisual that requested loading. + */ + void Remove( std::size_t id, TextureUploadObserver* textureObserver ); + +private: + + NPatchData::NPatchDataId GenerateUniqueNPatchDataId(); + + int32_t GetCacheIndexFromId( const NPatchData::NPatchDataId id ); protected: @@ -143,8 +121,8 @@ protected: private: - OwnerContainer< Data* > mCache; - + NPatchData::NPatchDataId mCurrentNPatchDataId; + OwnerContainer< NPatchData* > mCache; }; } // name Internal diff --git a/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp b/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp index 5c03ac2..6dcf020 100644 --- a/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp +++ b/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp @@ -24,7 +24,6 @@ #include // INTERNAL INCLUDES -#include #include #include #include @@ -278,15 +277,15 @@ void NPatchVisual::LoadImages() TextureManager& textureManager = mFactoryCache.GetTextureManager(); bool synchronousLoading = mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; - if( NPatchLoader::UNINITIALIZED_ID == mId && mImageUrl.IsLocalResource() ) + if( mId == NPatchData::INVALID_NPATCH_DATA_ID && mImageUrl.IsLocalResource() ) { bool preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader ? true : false; mId = mLoader.Load( textureManager, this, mImageUrl.GetUrl(), mBorder, preMultiplyOnLoad, synchronousLoading ); - const NPatchLoader::Data* data; - if( mLoader.GetNPatchData( mId, data ) && data->loadCompleted ) + const NPatchData* data; + if( mLoader.GetNPatchData( mId, data ) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE ) { - EnablePreMultipliedAlpha( preMultiplyOnLoad ); + EnablePreMultipliedAlpha( data->IsPreMultiplied() ); } } @@ -306,11 +305,11 @@ void NPatchVisual::GetNaturalSize( Vector2& naturalSize ) naturalSize.y = 0u; // load now if not already loaded - const NPatchLoader::Data* data; - if( mLoader.GetNPatchData( mId, data ) && data->loadCompleted ) + const NPatchData* data; + if( mLoader.GetNPatchData( mId, data ) && data->GetLoadingState() != NPatchData::LoadingState::LOADING ) { - naturalSize.x = data->croppedWidth; - naturalSize.y = data->croppedHeight; + naturalSize.x = data->GetCroppedWidth(); + naturalSize.y = data->GetCroppedHeight(); } else { @@ -386,6 +385,12 @@ void NPatchVisual::DoSetProperties( const Property::Map& propertyMap ) mImpl->mFlags &= ~Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; } } + + Property::Value* releasePolicy = propertyMap.Find( Toolkit::ImageVisual::Property::RELEASE_POLICY, RELEASE_POLICY_NAME ); + if( releasePolicy ) + { + releasePolicy->Get( mReleasePolicy ); + } } void NPatchVisual::DoSetOnScene( Actor& actor ) @@ -393,7 +398,7 @@ void NPatchVisual::DoSetOnScene( Actor& actor ) // load when first go on stage LoadImages(); - const NPatchLoader::Data* data; + const NPatchData* data; if( mLoader.GetNPatchData( mId, data ) ) { Geometry geometry = CreateGeometry(); @@ -402,11 +407,11 @@ void NPatchVisual::DoSetOnScene( Actor& actor ) mImpl->mRenderer = Renderer::New( geometry, shader ); mPlacementActor = actor; - if( data->loadCompleted ) + if( data->GetLoadingState() != NPatchData::LoadingState::LOADING ) { if( RenderingAddOn::Get().IsValid() ) { - RenderingAddOn::Get().SubmitRenderTask( mImpl->mRenderer, data->renderingMap ); + RenderingAddOn::Get().SubmitRenderTask( mImpl->mRenderer, data->GetRenderingMap() ); } ApplyTextureAndUniforms(); @@ -421,6 +426,13 @@ void NPatchVisual::DoSetOnScene( Actor& actor ) void NPatchVisual::DoSetOffScene( Actor& actor ) { + if((mId != NPatchData::INVALID_NPATCH_DATA_ID) && mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED) + { + mLoader.Remove(mId, this); + mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING; + mId = NPatchData::INVALID_NPATCH_DATA_ID; + } + actor.RemoveRenderer( mImpl->mRenderer ); mImpl->mRenderer.Reset(); mPlacementActor.Reset(); @@ -443,6 +455,7 @@ void NPatchVisual::DoCreatePropertyMap( Property::Map& map ) const map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl() ); map.Insert( Toolkit::ImageVisual::Property::BORDER_ONLY, mBorderOnly ); map.Insert( Toolkit::ImageVisual::Property::BORDER, mBorder ); + map.Insert( Toolkit::ImageVisual::Property::RELEASE_POLICY, mReleasePolicy ); if( mAuxiliaryUrl.IsValid() ) { @@ -466,25 +479,31 @@ NPatchVisual::NPatchVisual( VisualFactoryCache& factoryCache ) mLoader( factoryCache.GetNPatchLoader() ), mImageUrl(), mAuxiliaryUrl(), - mId( NPatchLoader::UNINITIALIZED_ID ), + mId(NPatchData::INVALID_NPATCH_DATA_ID), mBorderOnly( false ), mBorder(), - mAuxiliaryImageAlpha( 0.0f ) + mAuxiliaryImageAlpha( 0.0f ), + mReleasePolicy( Toolkit::ImageVisual::ReleasePolicy::DETACHED ) { EnablePreMultipliedAlpha( mFactoryCache.GetPreMultiplyOnLoad() ); } NPatchVisual::~NPatchVisual() { + if((mId != NPatchData::INVALID_NPATCH_DATA_ID) && ( mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::NEVER )) + { + mLoader.Remove(mId, this); + mId = NPatchData::INVALID_NPATCH_DATA_ID; + } } Geometry NPatchVisual::CreateGeometry() { Geometry geometry; - const NPatchLoader::Data* data; - if( mLoader.GetNPatchData( mId, data ) && data->loadCompleted ) + const NPatchData* data; + if( mLoader.GetNPatchData( mId, data ) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE ) { - if( data->stretchPixelsX.Size() == 1 && data->stretchPixelsY.Size() == 1 ) + if( data->GetStretchPixelsX().Size() == 1 && data->GetStretchPixelsY().Size() == 1 ) { if( DALI_UNLIKELY( mBorderOnly ) ) { @@ -492,13 +511,13 @@ Geometry NPatchVisual::CreateGeometry() } else { - if( data->renderingMap ) + if( data->GetRenderingMap() ) { uint32_t elementCount[2]; - geometry = RenderingAddOn::Get().CreateGeometryGrid(data->renderingMap, Uint16Pair(3, 3), elementCount ); + geometry = RenderingAddOn::Get().CreateGeometryGrid(data->GetRenderingMap(), Uint16Pair(3, 3), elementCount ); if( mImpl->mRenderer ) { - RenderingAddOn::Get().SubmitRenderTask(mImpl->mRenderer, data->renderingMap); + RenderingAddOn::Get().SubmitRenderTask(mImpl->mRenderer, data->GetRenderingMap()); } } else @@ -507,10 +526,10 @@ Geometry NPatchVisual::CreateGeometry() } } } - else if( data->stretchPixelsX.Size() > 0 || data->stretchPixelsY.Size() > 0) + else if( data->GetStretchPixelsX().Size() > 0 || data->GetStretchPixelsY().Size() > 0) { - Uint16Pair gridSize( 2 * data->stretchPixelsX.Size() + 1, 2 * data->stretchPixelsY.Size() + 1 ); - if( !data->renderingMap ) + Uint16Pair gridSize( 2 * data->GetStretchPixelsX().Size() + 1, 2 * data->GetStretchPixelsY().Size() + 1 ); + if( !data->GetRenderingMap() ) { geometry = !mBorderOnly ? CreateGridGeometry( gridSize ) : CreateBorderGeometry( gridSize ); } @@ -518,10 +537,10 @@ Geometry NPatchVisual::CreateGeometry() { uint32_t elementCount[2]; geometry = !mBorderOnly ? - RenderingAddOn::Get().CreateGeometryGrid(data->renderingMap, gridSize, elementCount ) : CreateBorderGeometry(gridSize ); + RenderingAddOn::Get().CreateGeometryGrid(data->GetRenderingMap(), gridSize, elementCount ) : CreateBorderGeometry(gridSize ); if( mImpl->mRenderer ) { - RenderingAddOn::Get().SubmitRenderTask(mImpl->mRenderer, data->renderingMap); + RenderingAddOn::Get().SubmitRenderTask(mImpl->mRenderer, data->GetRenderingMap()); } } } @@ -537,7 +556,7 @@ Geometry NPatchVisual::CreateGeometry() Shader NPatchVisual::CreateShader() { Shader shader; - const NPatchLoader::Data* data; + const NPatchData* data; // 0 is either no data (load failed?) or no stretch regions on image // for both cases we use the default shader NPatchUtility::StretchRanges::SizeType xStretchCount = 0; @@ -551,8 +570,8 @@ Shader NPatchVisual::CreateShader() // ask loader for the regions if( mLoader.GetNPatchData( mId, data ) ) { - xStretchCount = data->stretchPixelsX.Count(); - yStretchCount = data->stretchPixelsY.Count(); + xStretchCount = data->GetStretchPixelsX().Count(); + yStretchCount = data->GetStretchPixelsY().Count(); } if( DALI_LIKELY( !mImpl->mCustomShader ) ) @@ -616,25 +635,25 @@ Shader NPatchVisual::CreateShader() void NPatchVisual::ApplyTextureAndUniforms() { - const NPatchLoader::Data* data; + const NPatchData* data; TextureSet textureSet; - if( mLoader.GetNPatchData( mId, data ) && data->loadCompleted ) + if( mLoader.GetNPatchData( mId, data ) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE ) { - textureSet = data->textureSet; + textureSet = data->GetTextures(); - if( data->stretchPixelsX.Size() == 1 && data->stretchPixelsY.Size() == 1 ) + if( data->GetStretchPixelsX().Size() == 1 && data->GetStretchPixelsY().Size() == 1 ) { //special case for 9 patch - Uint16Pair stretchX = data->stretchPixelsX[ 0 ]; - Uint16Pair stretchY = data->stretchPixelsY[ 0 ]; + Uint16Pair stretchX = data->GetStretchPixelsX()[ 0 ]; + Uint16Pair stretchY = data->GetStretchPixelsY()[ 0 ]; uint16_t stretchWidth = ( stretchX.GetY() >= stretchX.GetX() ) ? stretchX.GetY() - stretchX.GetX() : 0; uint16_t stretchHeight = ( stretchY.GetY() >= stretchY.GetX() ) ? stretchY.GetY() - stretchY.GetX() : 0; mImpl->mRenderer.RegisterProperty( "uFixed[0]", Vector2::ZERO ); mImpl->mRenderer.RegisterProperty( "uFixed[1]", Vector2( stretchX.GetX(), stretchY.GetX()) ); - mImpl->mRenderer.RegisterProperty( "uFixed[2]", Vector2( data->croppedWidth - stretchWidth, data->croppedHeight - stretchHeight ) ); + mImpl->mRenderer.RegisterProperty( "uFixed[2]", Vector2( data->GetCroppedWidth() - stretchWidth, data->GetCroppedHeight() - stretchHeight ) ); mImpl->mRenderer.RegisterProperty( "uStretchTotal", Vector2( stretchWidth, stretchHeight ) ); } else @@ -642,8 +661,8 @@ void NPatchVisual::ApplyTextureAndUniforms() mImpl->mRenderer.RegisterProperty( "uNinePatchFactorsX[0]", Vector2::ZERO ); mImpl->mRenderer.RegisterProperty( "uNinePatchFactorsY[0]", Vector2::ZERO ); - RegisterStretchProperties( mImpl->mRenderer, "uNinePatchFactorsX", data->stretchPixelsX, data->croppedWidth ); - RegisterStretchProperties( mImpl->mRenderer, "uNinePatchFactorsY", data->stretchPixelsY, data->croppedHeight ); + RegisterStretchProperties( mImpl->mRenderer, "uNinePatchFactorsX", data->GetStretchPixelsX(), data->GetCroppedWidth() ); + RegisterStretchProperties( mImpl->mRenderer, "uNinePatchFactorsY", data->GetStretchPixelsY(), data->GetCroppedHeight() ); } } else @@ -664,10 +683,10 @@ void NPatchVisual::ApplyTextureAndUniforms() // If the auxiliary image is smaller than the un-stretched NPatch, use CPU resizing to enlarge it to the // same size as the unstretched NPatch. This will give slightly higher quality results than just relying // on GL interpolation alone. - if( mAuxiliaryPixelBuffer.GetWidth() < data->croppedWidth && - mAuxiliaryPixelBuffer.GetHeight() < data->croppedHeight ) + if( mAuxiliaryPixelBuffer.GetWidth() < data->GetCroppedWidth() && + mAuxiliaryPixelBuffer.GetHeight() < data->GetCroppedHeight() ) { - mAuxiliaryPixelBuffer.Resize( data->croppedWidth, data->croppedHeight ); + mAuxiliaryPixelBuffer.Resize( data->GetCroppedWidth(), data->GetCroppedHeight() ); } // Note, this resets mAuxiliaryPixelBuffer handle @@ -838,7 +857,7 @@ Geometry NPatchVisual::CreateBorderGeometry( Uint16Pair gridSize ) void NPatchVisual::SetResource() { - const NPatchLoader::Data* data; + const NPatchData* data; if( mImpl->mRenderer && mLoader.GetNPatchData( mId, data ) ) { Geometry geometry = CreateGeometry(); @@ -860,35 +879,32 @@ void NPatchVisual::SetResource() } } +void NPatchVisual::UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing, const Vector4& atlasRect, bool preMultiplied ) +{ + EnablePreMultipliedAlpha( preMultiplied ); + if(!loadSuccess) + { + // Image loaded and ready to display + ResourceReady( Toolkit::Visual::ResourceStatus::FAILED ); + } + + if( mAuxiliaryPixelBuffer || !mAuxiliaryUrl.IsValid() ) + { + SetResource(); + } +} + void NPatchVisual::LoadComplete( bool loadSuccess, Devel::PixelBuffer pixelBuffer, const VisualUrl& url, bool preMultiplied ) { - if( url.GetUrl() == mAuxiliaryUrl.GetUrl() ) + if( loadSuccess && url.GetUrl() == mAuxiliaryUrl.GetUrl() ) { mAuxiliaryPixelBuffer = pixelBuffer; - const NPatchLoader::Data* data; - if( mLoader.GetNPatchData( mId, data ) && data->loadCompleted ) - { - SetResource(); - } + SetResource(); } else { - Devel::PixelBuffer loadedPixelBuffer; - if( loadSuccess ) - { - loadedPixelBuffer = pixelBuffer; - EnablePreMultipliedAlpha( preMultiplied ); - } - else - { - loadedPixelBuffer = LoadImageFromFile( mFactoryCache.GetTextureManager().GetBrokenImageUrl() ); - } - mLoader.SetNPatchData( loadSuccess, mId, loadedPixelBuffer, url, preMultiplied ); - - if( mAuxiliaryPixelBuffer || !mAuxiliaryUrl.IsValid() ) - { - SetResource(); - } + // Image loaded and ready to display + ResourceReady( Toolkit::Visual::ResourceStatus::FAILED ); } } diff --git a/dali-toolkit/internal/visuals/npatch/npatch-visual.h b/dali-toolkit/internal/visuals/npatch/npatch-visual.h index 41252f6..19bdaff 100644 --- a/dali-toolkit/internal/visuals/npatch/npatch-visual.h +++ b/dali-toolkit/internal/visuals/npatch/npatch-visual.h @@ -27,6 +27,7 @@ #include // INTERNAL INCLUDES +#include #include #include #include @@ -211,7 +212,7 @@ private: * To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready. * This callback is the place to add the renderer as it would be called once the loading is finished. */ - void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing, const Vector4& atlasRect, bool preMultiplied ) override {} + void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing, const Vector4& atlasRect, bool preMultiplied ) override; /** * @copydoc TextureUploadObserver::LoadComplete @@ -222,16 +223,16 @@ private: void LoadComplete( bool loadSuccess, Devel::PixelBuffer pixelBuffer, const VisualUrl& url, bool preMultiplied ) override; private: - - WeakHandle mPlacementActor; ///< Weakhandle to contain Actor during texture loading - NPatchLoader& mLoader; ///< reference to N patch loader for fast access - VisualUrl mImageUrl; ///< The url to the N patch to load - VisualUrl mAuxiliaryUrl; ///< An auxiliary image that can be displayed on top of the N-Patch - std::size_t mId; ///< id of the N patch (from loader/cache) - Devel::PixelBuffer mAuxiliaryPixelBuffer; ///< pixel buffer of the auxiliary mask image - bool mBorderOnly; ///< if only border is desired - Rect mBorder; ///< The size of the border - float mAuxiliaryImageAlpha; ///< The alpha value for the auxiliary image only + WeakHandle mPlacementActor; ///< Weakhandle to contain Actor during texture loading + NPatchLoader& mLoader; ///< reference to N patch loader for fast access + VisualUrl mImageUrl; ///< The url to the N patch to load + VisualUrl mAuxiliaryUrl; ///< An auxiliary image that can be displayed on top of the N-Patch + NPatchData::NPatchDataId mId; ///< id of the N patch (from loader/cache) + Devel::PixelBuffer mAuxiliaryPixelBuffer; ///< pixel buffer of the auxiliary mask image + bool mBorderOnly; ///< if only border is desired + Rect mBorder; ///< The size of the border + float mAuxiliaryImageAlpha; ///< The alpha value for the auxiliary image only + Toolkit::ImageVisual::ReleasePolicy::Type mReleasePolicy; ///< The release policy to determine when an image should no longer be cached. }; } // namespace Internal diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.cpp b/dali-toolkit/internal/visuals/texture-manager-impl.cpp index ea0abc1..bcde348 100644 --- a/dali-toolkit/internal/visuals/texture-manager-impl.cpp +++ b/dali-toolkit/internal/visuals/texture-manager-impl.cpp @@ -999,7 +999,6 @@ void TextureManager::PostLoad( TextureInfo& textureInfo, Devel::PixelBuffer& pix } else { - // @todo If the load was unsuccessful, upload the broken image. textureInfo.loadState = LoadState::LOAD_FAILED; CheckForWaitingTexture( textureInfo ); NotifyObservers( textureInfo, false ); @@ -1382,11 +1381,6 @@ void TextureManager::SetBrokenImageUrl(const std::string& brokenImageUrl) mBrokenImageUrl = brokenImageUrl; } -const std::string TextureManager::GetBrokenImageUrl() -{ - return mBrokenImageUrl; -} - Geometry TextureManager::GetRenderGeometry(TextureId textureId, uint32_t& frontElements, uint32_t& backElements ) { return RenderingAddOn::Get().IsValid() ? diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.h b/dali-toolkit/internal/visuals/texture-manager-impl.h index 28e0869..89a8ed0 100644 --- a/dali-toolkit/internal/visuals/texture-manager-impl.h +++ b/dali-toolkit/internal/visuals/texture-manager-impl.h @@ -428,12 +428,6 @@ public: void SetBrokenImageUrl(const std::string& brokenImageUrl); /** - * @brief Get an image to be used when a visual has failed to correctly render - * @return Returns The broken image url. - */ - const std::string GetBrokenImageUrl(); - - /** * @brief Returns the geometry associated with texture. * @param[in] textureId Id of the texture * @param[out] frontElements number of front elements -- 2.7.4