Request load texture again if the observer is destroyed during loading. ref/for/devel/master
authorSeungho Baek <sbsh.baek@samsung.com>
Mon, 30 Nov 2020 05:45:41 +0000 (14:45 +0900)
committerSeungho Baek <sbsh.baek@samsung.com>
Mon, 30 Nov 2020 10:24:27 +0000 (19:24 +0900)
Change-Id: I0879a9eaa62aac8533fbc6b8d9416805ab7a0675
Signed-off-by: Seungho Baek <sbsh.baek@samsung.com>
dali-toolkit/internal/visuals/npatch-loader.cpp
dali-toolkit/internal/visuals/npatch-loader.h
dali-toolkit/internal/visuals/npatch/npatch-visual.cpp
dali-toolkit/internal/visuals/npatch/npatch-visual.h

index 2550001..3ab8cad 100644 (file)
@@ -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
index a3aa464..51f2482 100644 (file)
@@ -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:
 
   /**
index 5c03ac2..6823cb8 100644 (file)
@@ -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();
   }
 }
 
index 41252f6..835f724 100644 (file)
@@ -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<Actor>  mPlacementActor;       ///< Weakhandle to contain Actor during texture loading