[Tizen] Refactoring Animated image visual 11/267311/26
authorseungho <sbsh.baek@samsung.com>
Wed, 1 Dec 2021 08:20:05 +0000 (17:20 +0900)
committerseungho <sbsh.baek@samsung.com>
Tue, 28 Dec 2021 10:08:55 +0000 (19:08 +0900)
 - Animated image file will be opened when the visual is on scene.
 - Cache first frame only to cache single frame image as like image visual.
 - Pause timer when next frame is not cached yet. And resume it after the frame is ready.
 - Load policy and release policy is now supported.

Change-Id: I86548fc0d1952a70959f710a7005eb1d4b66624b
Signed-off-by: seungho <sbsh.baek@samsung.com>
13 files changed:
dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp
dali-toolkit/internal/visuals/animated-image/animated-image-visual.h
dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h
dali-toolkit/internal/visuals/animated-image/image-cache.cpp
dali-toolkit/internal/visuals/animated-image/image-cache.h
dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.h
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h
dali-toolkit/internal/visuals/texture-manager-impl.cpp
dali-toolkit/internal/visuals/texture-manager-impl.h
dali-toolkit/internal/visuals/texture-upload-observer.h

index da7fb09..cc90d5d 100644 (file)
@@ -61,8 +61,25 @@ DALI_ENUM_TO_STRING_TABLE_BEGIN(WRAP_MODE)
   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::WrapMode, MIRRORED_REPEAT)
 DALI_ENUM_TO_STRING_TABLE_END(WRAP_MODE)
 
-const Vector4  FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
-constexpr auto LOOP_FOREVER = -1;
+// load policies
+DALI_ENUM_TO_STRING_TABLE_BEGIN(LOAD_POLICY)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::LoadPolicy, IMMEDIATE)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::LoadPolicy, ATTACHED)
+DALI_ENUM_TO_STRING_TABLE_END(LOAD_POLICY)
+
+// release policies
+DALI_ENUM_TO_STRING_TABLE_BEGIN(RELEASE_POLICY)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::ReleasePolicy, DETACHED)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::ReleasePolicy, DESTROYED)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::ReleasePolicy, NEVER)
+DALI_ENUM_TO_STRING_TABLE_END(RELEASE_POLICY)
+
+static constexpr uint32_t SINGLE_IMAGE_COUNT = 1u;
+static constexpr uint32_t FIRST_FRAME_INDEX  = 0u;
+static constexpr uint16_t MINIMUM_CACHESIZE  = 1;
+static constexpr Vector4  FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
+static constexpr auto     LOOP_FOREVER = -1;
+static constexpr auto     FIRST_LOOP   = 0u;
 
 #if defined(DEBUG_ENABLED)
 Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ANIMATED_IMAGE");
@@ -74,9 +91,7 @@ Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "
  *
  *   | New
  *   |   DoSetProperties()
- *   |   LoadFirstBatch()
  *   |     new cache
- *   |       cache->LoadBatch()
  *   |
  *   | DoSetOnScene()
  *   |   PrepareTextureSet()
@@ -85,7 +100,7 @@ Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "
  *   |   StartFirstFrame()
  *   |
  *   | FrameReady(textureSet)
- *   |   start first frame:
+ *   |   StartFirstFrame:
  *   |     actor.AddRenderer
  *   |     start timer
  *   |   mRenderer.SetTextures(textureSet)
@@ -95,8 +110,7 @@ Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "
  *   |     if front frame is ready,
  *   |       mRenderer.SetTextures( front frame's texture )
  *   |     else
- *   |       mWaitingForTexture=true
- *   |     cache->LoadBatch()
+ *   |       Waiting for frame ready.
  *   |
  *   | FrameReady(textureSet)
  *   |   mRenderer.SetTextures(textureSet)
@@ -110,11 +124,6 @@ AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache
   visual->InitializeAnimatedImage(imageUrl);
   visual->SetProperties(properties);
 
-  if(visual->mFrameCount > 0)
-  {
-    visual->LoadFirstBatch();
-  }
-
   visual->Initialize();
 
   return visual;
@@ -136,11 +145,6 @@ AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache
   visual->mFrameCount = imageUrls.Count();
   visual->SetProperties(properties);
 
-  if(visual->mFrameCount > 0)
-  {
-    visual->LoadFirstBatch();
-  }
-
   visual->Initialize();
 
   return visual;
@@ -151,11 +155,6 @@ AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache
   AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory));
   visual->InitializeAnimatedImage(imageUrl);
 
-  if(visual->mFrameCount > 0)
-  {
-    visual->LoadFirstBatch();
-  }
-
   visual->Initialize();
 
   return visual;
@@ -163,9 +162,41 @@ AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache
 
 void AnimatedImageVisual::InitializeAnimatedImage(const VisualUrl& imageUrl)
 {
-  mImageUrl             = imageUrl;
+  mImageUrl = imageUrl;
   mAnimatedImageLoading = AnimatedImageLoading::New(imageUrl.GetUrl(), imageUrl.IsLocalResource());
-  mFrameCount           = mAnimatedImageLoading.GetImageCount();
+}
+
+void AnimatedImageVisual::CreateImageCache()
+{
+  DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::CreateImageCache()  batchSize:%d  cacheSize:%d\n", mBatchSize, mCacheSize);
+
+  TextureManager& textureManager = mFactoryCache.GetTextureManager();
+
+  if(mAnimatedImageLoading)
+  {
+    mImageCache = new RollingAnimatedImageCache(textureManager, mAnimatedImageLoading, *this, mCacheSize, mBatchSize, IsSynchronousLoadingRequired());
+  }
+  else if(mImageUrls)
+  {
+    // Ensure the batch size and cache size are no bigger than the number of URLs,
+    // and that the cache is at least as big as the batch size.
+    uint16_t numUrls   = mImageUrls->size();
+    uint16_t batchSize = std::max(std::min(mBatchSize, numUrls), MINIMUM_CACHESIZE);
+    uint16_t cacheSize = std::max(std::min(std::max(batchSize, mCacheSize), numUrls), MINIMUM_CACHESIZE);
+    if(cacheSize < numUrls)
+    {
+      mImageCache = new RollingImageCache(textureManager, *mImageUrls, *this, cacheSize, batchSize, mFrameDelay);
+    }
+    else
+    {
+      mImageCache = new FixedImageCache(textureManager, *mImageUrls, *this, batchSize, mFrameDelay);
+    }
+  }
+
+  if(!mImageCache)
+  {
+    DALI_LOG_ERROR("mImageCache is null\n");
+  }
 }
 
 AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory)
@@ -177,14 +208,16 @@ AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, Image
   mImageUrl(),
   mAnimatedImageLoading(),
   mFrameIndexForJumpTo(0),
+  mCurrentFrameIndex(FIRST_FRAME_INDEX),
   mImageUrls(NULL),
   mImageCache(NULL),
   mCacheSize(2),
   mBatchSize(2),
   mFrameDelay(100),
   mLoopCount(LOOP_FOREVER),
-  mCurrentLoopIndex(0),
-  mUrlIndex(0),
+  mCurrentLoopIndex(FIRST_LOOP),
+  mLoadPolicy(Toolkit::ImageVisual::LoadPolicy::ATTACHED),
+  mReleasePolicy(Toolkit::ImageVisual::ReleasePolicy::DETACHED),
   mFrameCount(0),
   mImageSize(),
   mActionStatus(DevelAnimatedImageVisual::Action::PLAY),
@@ -198,6 +231,12 @@ AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, Image
 
 AnimatedImageVisual::~AnimatedImageVisual()
 {
+  // AnimatedImageVisual destroyed so remove texture unless ReleasePolicy is set to never release
+  // If this is animated image, clear cache. Else if this is single frame image, this is affected be release policy.
+  if(mFrameCount > SINGLE_IMAGE_COUNT || mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::NEVER)
+  {
+    mImageCache->ClearCache();
+  }
   delete mImageCache;
   delete mImageUrls;
 }
@@ -208,7 +247,14 @@ void AnimatedImageVisual::GetNaturalSize(Vector2& naturalSize)
   {
     if(mImageUrl.IsValid())
     {
-      mImageSize = mAnimatedImageLoading.GetImageSize();
+      if(mAnimatedImageLoading.HasLoadingSucceeded())
+      {
+        mImageSize = mAnimatedImageLoading.GetImageSize();
+      }
+      else
+      {
+        mImageSize = Dali::GetClosestImageSize(mImageUrl.GetUrl());
+      }
     }
     else if(mImageUrls && mImageUrls->size() > 0)
     {
@@ -256,6 +302,9 @@ void AnimatedImageVisual::DoCreatePropertyMap(Property::Map& map) const
   map.Insert(Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, (mImageCache) ? static_cast<int32_t>(mImageCache->GetTotalFrameCount()) : -1);
 
   map.Insert(Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, mStopBehavior);
+
+  map.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, mLoadPolicy);
+  map.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, mReleasePolicy);
 }
 
 void AnimatedImageVisual::DoCreateInstancePropertyMap(Property::Map& map) const
@@ -294,6 +343,7 @@ void AnimatedImageVisual::OnDoAction(const Dali::Property::Index actionId, const
       // STOP reset functionality will actually be done in a future change
       // Stop will be executed on next timer tick
       mActionStatus = DevelAnimatedImageVisual::Action::STOP;
+      mCurrentLoopIndex = FIRST_LOOP;
       if(IsOnScene())
       {
         DisplayNextFrame();
@@ -368,8 +418,25 @@ void AnimatedImageVisual::DoSetProperties(const Property::Map& propertyMap)
       {
         DoSetProperty(Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, keyValue.second);
       }
+      else if(keyValue.first == LOAD_POLICY_NAME)
+      {
+        DoSetProperty(Toolkit::ImageVisual::Property::LOAD_POLICY, keyValue.second);
+      }
+      else if(keyValue.first == RELEASE_POLICY_NAME)
+      {
+        DoSetProperty(Toolkit::ImageVisual::Property::RELEASE_POLICY, keyValue.second);
+      }
+      else if(keyValue.first == SYNCHRONOUS_LOADING)
+      {
+        DoSetProperty(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second);
+      }
     }
   }
+  // Load image immediately if LOAD_POLICY requires it
+  if(mLoadPolicy == Toolkit::ImageVisual::LoadPolicy::IMMEDIATE)
+  {
+    PrepareTextureSet();
+  }
 }
 
 void AnimatedImageVisual::DoSetProperty(Property::Index        index,
@@ -449,6 +516,10 @@ void AnimatedImageVisual::DoSetProperty(Property::Index        index,
       if(value.Get(frameDelay))
       {
         mFrameDelay = frameDelay;
+        if(mImageCache)
+        {
+          mImageCache->SetInterval(static_cast<uint32_t>(mFrameDelay));
+        }
       }
       break;
     }
@@ -487,28 +558,42 @@ void AnimatedImageVisual::DoSetProperty(Property::Index        index,
       }
       break;
     }
+
+    case Toolkit::ImageVisual::Property::RELEASE_POLICY:
+    {
+      int releasePolicy = 0;
+      Scripting::GetEnumerationProperty(value, RELEASE_POLICY_TABLE, RELEASE_POLICY_TABLE_COUNT, releasePolicy);
+      mReleasePolicy = Toolkit::ImageVisual::ReleasePolicy::Type(releasePolicy);
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::LOAD_POLICY:
+    {
+      int loadPolicy = 0;
+      Scripting::GetEnumerationProperty(value, LOAD_POLICY_TABLE, LOAD_POLICY_TABLE_COUNT, loadPolicy);
+      mLoadPolicy = Toolkit::ImageVisual::LoadPolicy::Type(loadPolicy);
+      break;
+    }
   }
 }
 
 void AnimatedImageVisual::DoSetOnScene(Actor& actor)
 {
+  mStartFirstFrame      = true;
   mPlacementActor       = actor;
   TextureSet textureSet = PrepareTextureSet();
 
   // Loading animated image file is failed.
-  if(!mImageCache ||
-     (mAnimatedImageLoading && !mAnimatedImageLoading.HasLoadingSucceeded()))
+  if(!mImageCache || mImageCache->GetLoadState() == TextureManager::LoadState::LOAD_FAILED)
   {
     textureSet = SetLoadingFailed();
   }
 
-  if(textureSet) // if the image loading is successful
+  // If textureSet is prepared and first frame still not started,
+  // make first frame start.
+  if(textureSet && mStartFirstFrame)
   {
-    StartFirstFrame(textureSet);
-  }
-  else
-  {
-    mStartFirstFrame = true;
+    StartFirstFrame(textureSet, mImageCache->GetFrameInterval(FIRST_FRAME_INDEX));
   }
 }
 
@@ -523,8 +608,19 @@ void AnimatedImageVisual::DoSetOffScene(Actor& actor)
   }
 
   actor.RemoveRenderer(mImpl->mRenderer);
+  if(mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED)
+  {
+    mImageCache->ClearCache(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas
+    mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING;
+
+    TextureSet textureSet = TextureSet::New();
+    mImpl->mRenderer.SetTextures(textureSet);
+  }
+
   mPlacementActor.Reset();
   mStartFirstFrame = false;
+  mCurrentFrameIndex = FIRST_FRAME_INDEX;
+  mCurrentLoopIndex = FIRST_LOOP;
 }
 
 void AnimatedImageVisual::OnSetTransform()
@@ -546,6 +642,8 @@ void AnimatedImageVisual::UpdateShader()
 
 void AnimatedImageVisual::OnInitialize()
 {
+  CreateImageCache();
+
   bool   defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
   Shader shader          = GenerateShader();
 
@@ -569,61 +667,7 @@ void AnimatedImageVisual::OnInitialize()
   }
 }
 
-void AnimatedImageVisual::LoadFirstBatch()
-{
-  // Ensure the batch size and cache size are no bigger than the number of URLs,
-  // and that the cache is at least as big as the batch size.
-  uint16_t numUrls   = 0;
-  uint16_t batchSize = 1;
-  uint16_t cacheSize = 1;
-
-  if(mImageUrls)
-  {
-    numUrls = mImageUrls->size();
-  }
-  else
-  {
-    numUrls = mFrameCount;
-  }
-
-  batchSize = std::min(mBatchSize, numUrls);
-  cacheSize = std::min(std::max(batchSize, mCacheSize), numUrls);
-
-  DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::LoadFirstBatch()  batchSize:%d  cacheSize:%d\n", batchSize, cacheSize);
-
-  mUrlIndex                      = 0;
-  TextureManager& textureManager = mFactoryCache.GetTextureManager();
-
-  if(mAnimatedImageLoading)
-  {
-    mImageCache = new RollingAnimatedImageCache(textureManager, mAnimatedImageLoading, mFrameCount, *this, cacheSize, batchSize, IsSynchronousLoadingRequired());
-  }
-  else if(mImageUrls)
-  {
-    if(batchSize > 0 && cacheSize > 0)
-    {
-      if(cacheSize < numUrls)
-      {
-        mImageCache = new RollingImageCache(textureManager, *mImageUrls, *this, cacheSize, batchSize);
-      }
-      else
-      {
-        mImageCache = new FixedImageCache(textureManager, *mImageUrls, *this, batchSize);
-      }
-    }
-    else
-    {
-      mImageCache = new RollingImageCache(textureManager, *mImageUrls, *this, 1, 1);
-    }
-  }
-
-  if(!mImageCache)
-  {
-    DALI_LOG_ERROR("mImageCache is null\n");
-  }
-}
-
-void AnimatedImageVisual::StartFirstFrame(TextureSet& textureSet)
+void AnimatedImageVisual::StartFirstFrame(TextureSet& textureSet, uint32_t firstInterval)
 {
   DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::StartFirstFrame()\n");
 
@@ -640,23 +684,20 @@ void AnimatedImageVisual::StartFirstFrame(TextureSet& textureSet)
     }
   }
 
-  if(mFrameCount > 1)
+  if(mImpl->mResourceStatus != Toolkit::Visual::ResourceStatus::FAILED)
   {
-    int frameDelay = mImageCache->GetFrameInterval(0);
-    if(frameDelay == 0u)
+    if(mFrameCount > SINGLE_IMAGE_COUNT)
     {
-      frameDelay = mFrameDelay; // from URL array
+      mFrameDelayTimer = Timer::New(firstInterval);
+      mFrameDelayTimer.TickSignal().Connect(this, &AnimatedImageVisual::DisplayNextFrame);
+      mFrameDelayTimer.Start();
     }
-    mFrameDelayTimer = Timer::New(frameDelay);
-    mFrameDelayTimer.TickSignal().Connect(this, &AnimatedImageVisual::DisplayNextFrame);
-    mFrameDelayTimer.Start();
-  }
 
-  if(mImpl->mResourceStatus != Toolkit::Visual::ResourceStatus::FAILED)
-  {
     DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "ResourceReady(ResourceStatus::READY)\n");
     ResourceReady(Toolkit::Visual::ResourceStatus::READY);
   }
+
+  mCurrentFrameIndex = FIRST_FRAME_INDEX;
 }
 
 TextureSet AnimatedImageVisual::PrepareTextureSet()
@@ -667,6 +708,7 @@ TextureSet AnimatedImageVisual::PrepareTextureSet()
     textureSet = mImageCache->FirstFrame();
   }
 
+  // Check whether synchronous loading is true or false for the first frame.
   if(textureSet)
   {
     SetImageSize(textureSet);
@@ -688,24 +730,28 @@ void AnimatedImageVisual::SetImageSize(TextureSet& textureSet)
   }
 }
 
-void AnimatedImageVisual::FrameReady(TextureSet textureSet)
+void AnimatedImageVisual::FrameReady(TextureSet textureSet, uint32_t interval)
 {
   // When image visual requested to load new frame to mImageCache and it is failed.
   if(!textureSet)
   {
     textureSet = SetLoadingFailed();
   }
-
   SetImageSize(textureSet);
 
   if(mStartFirstFrame)
   {
-    StartFirstFrame(textureSet);
+    mFrameCount = mImageCache->GetTotalFrameCount();
+    StartFirstFrame(textureSet, interval);
   }
   else
   {
     if(mImpl->mRenderer)
     {
+      if(mFrameDelayTimer && interval > 0u)
+      {
+        mFrameDelayTimer.SetInterval(interval);
+      }
       mImpl->mRenderer.SetTextures(textureSet);
     }
   }
@@ -715,10 +761,8 @@ bool AnimatedImageVisual::DisplayNextFrame()
 {
   TextureSet textureSet;
   bool       continueTimer = false;
-
   if(mImageCache)
   {
-    bool     nextFrame  = false;
     uint32_t frameIndex = mImageCache->GetCurrentFrameIndex();
 
     if(mIsJumpTo)
@@ -732,10 +776,10 @@ bool AnimatedImageVisual::DisplayNextFrame()
     }
     else if(mActionStatus == DevelAnimatedImageVisual::Action::STOP)
     {
-      frameIndex = 0;
+      mCurrentLoopIndex = FIRST_LOOP;
       if(mStopBehavior == DevelImageVisual::StopBehavior::FIRST_FRAME)
       {
-        frameIndex = 0;
+        frameIndex = FIRST_FRAME_INDEX;
       }
       else if(mStopBehavior == DevelImageVisual::StopBehavior::LAST_FRAME)
       {
@@ -748,13 +792,12 @@ bool AnimatedImageVisual::DisplayNextFrame()
     }
     else
     {
-      if(mFrameCount > 1)
+      if(mFrameCount > SINGLE_IMAGE_COUNT)
       {
-        nextFrame = true;
         frameIndex++;
         if(frameIndex >= mFrameCount)
         {
-          frameIndex %= mFrameCount;
+          frameIndex = FIRST_FRAME_INDEX;
           ++mCurrentLoopIndex;
         }
 
@@ -765,38 +808,24 @@ bool AnimatedImageVisual::DisplayNextFrame()
           return DisplayNextFrame();
         }
       }
-
-      unsigned int delay = mImageCache->GetFrameInterval(frameIndex);
-      if(delay > 0u)
-      {
-        if(mFrameDelayTimer.GetInterval() != delay)
-        {
-          mFrameDelayTimer.SetInterval(delay);
-        }
-      }
     }
 
     DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::DisplayNextFrame(this:%p) CurrentFrameIndex:%d\n", this, frameIndex);
 
-    if(nextFrame)
-    {
-      textureSet = mImageCache->NextFrame();
-    }
-    else
-    {
-      textureSet = mImageCache->Frame(frameIndex);
-    }
-
-    continueTimer = (mActionStatus == DevelAnimatedImageVisual::Action::PLAY) ? true : false;
-  }
+    textureSet = mImageCache->Frame(frameIndex);
 
-  if(textureSet)
-  {
-    SetImageSize(textureSet);
-    if(mImpl->mRenderer)
+    if(textureSet)
     {
-      mImpl->mRenderer.SetTextures(textureSet);
+      SetImageSize(textureSet);
+      if(mImpl->mRenderer)
+      {
+        mImpl->mRenderer.SetTextures(textureSet);
+      }
+      mFrameDelayTimer.SetInterval(mImageCache->GetFrameInterval(frameIndex));
     }
+
+    mCurrentFrameIndex = frameIndex;
+    continueTimer      = (mActionStatus == DevelAnimatedImageVisual::Action::PLAY && textureSet) ? true : false;
   }
 
   return continueTimer;
index 1d21356..6679ef2 100644 (file)
@@ -193,54 +193,57 @@ protected:
 
 private:
   /**
-   * Creates the renderer for the animated image
+   * @brief Creates the renderer for the animated image
    */
   void CreateRenderer();
 
   /**
-   * Starts the Load of the first batch of URLs
-   */
-  void LoadFirstBatch();
-
-  /**
-   * Adds the texture set to the renderer, and the renderer to the
+   * @brief Adds the texture set to the renderer, and the renderer to the
    * placement actor, and starts the frame timer
-   * @param[in] textureSet The texture set to apply
+   * @param[in] textureSet    The texture set to apply
+   * @param[in] firstInterval frame interval for the first frame.
    */
-  void StartFirstFrame(TextureSet& textureSet);
+  void StartFirstFrame(TextureSet& textureSet, uint32_t firstInterval);
 
   /**
-   * Prepares the texture set for displaying
+   * @brief Prepares the texture set for displaying
+   * @return Prepared texture set if it is loaded.
    */
   TextureSet PrepareTextureSet();
 
   /**
-   * Set the image size from the texture set
+   * @brief Set the image size from the texture set
    * @param[in] textureSet The texture set to get the size from
    */
   void SetImageSize(TextureSet& textureSet);
 
   /**
-   * Called when the next frame is ready.
+   * @brief Called when the next frame is ready.
    * @param[in] textureSet the texture set to apply
+   * @param[in] interval interval for the frame
    */
-  void FrameReady(TextureSet textureSet) override;
+  void FrameReady(TextureSet textureSet, uint32_t interval) override;
 
   /**
-   * Display the next frame. It is called when the mFrameDelayTimer ticks.
-   * Returns true to ensure the timer continues running.
+   * @brief Display the next frame. It is called when the mFrameDelayTimer ticks.
+   * @return true to ensure the timer continues running.
    */
   bool DisplayNextFrame();
 
   /**
-   * Initialize the animated image variables.
+   * @brief Initialize the animated image variables.
    * @param[in] imageUrl The url of the animated image
    */
   void InitializeAnimatedImage(const VisualUrl& imageUrl);
 
   /**
-   * Set the state of loading fail of an image or a frame.
-   * Returns TextureSet of broken image.
+   * @brief Create image cache for animated image or image array.
+   */
+  void CreateImageCache();
+
+  /**
+   * @brief Set the state of loading fail of an image or a frame.
+   * @return TextureSet of broken image.
    */
   TextureSet SetLoadingFailed();
 
@@ -260,6 +263,7 @@ private:
   VisualUrl                  mImageUrl;
   Dali::AnimatedImageLoading mAnimatedImageLoading; // Only needed for animated image
   uint32_t                   mFrameIndexForJumpTo;  // Frame index into textureRects
+  uint32_t                   mCurrentFrameIndex;
 
   // Variables for Multi-Image player
   ImageCache::UrlList* mImageUrls;
@@ -269,7 +273,10 @@ private:
   uint16_t             mFrameDelay;
   int16_t              mLoopCount;
   int16_t              mCurrentLoopIndex;
-  uint16_t             mUrlIndex;
+
+  // Variables for image visual policy.
+  Dali::Toolkit::ImageVisual::LoadPolicy::Type    mLoadPolicy;
+  Dali::Toolkit::ImageVisual::ReleasePolicy::Type mReleasePolicy;
 
   // Shared variables
   uint32_t        mFrameCount; // Number of frames
index 4593bc7..c90e86e 100644 (file)
@@ -20,6 +20,9 @@
 // INTERNAL HEADERS
 #include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
 
+// EXTERNAL HEADERS
+#include <dali/integration-api/debug.h>
+
 namespace Dali
 {
 namespace Toolkit
@@ -28,33 +31,30 @@ namespace Internal
 {
 namespace
 {
-const bool ENABLE_ORIENTATION_CORRECTION(true);
+static constexpr bool ENABLE_ORIENTATION_CORRECTION(true);
+
+static constexpr uint32_t FIRST_FRAME_INDEX = 0u;
 } // namespace
 
 FixedImageCache::FixedImageCache(
-  TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer, unsigned int batchSize)
-: ImageCache(textureManager, observer, batchSize),
+  TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer, uint32_t batchSize, uint32_t interval)
+: ImageCache(textureManager, observer, batchSize, interval),
   mImageUrls(urlList),
-  mFront(0u)
+  mFront(FIRST_FRAME_INDEX)
 {
+  mLoadStates.assign(mImageUrls.size(), TextureManager::LoadState::NOT_STARTED);
   mReadyFlags.reserve(mImageUrls.size());
-  LoadBatch();
 }
 
 FixedImageCache::~FixedImageCache()
 {
-  if(mTextureManagerAlive)
-  {
-    for(std::size_t i = 0; i < mImageUrls.size(); ++i)
-    {
-      mTextureManager.Remove(mImageUrls[i].mTextureId, this);
-    }
-  }
+  ClearCache();
 }
 
 TextureSet FixedImageCache::Frame(uint32_t frameIndex)
 {
-  while(frameIndex > mFront)
+  while(frameIndex > mFront || mReadyFlags.empty() ||
+        (frameIndex == FIRST_FRAME_INDEX && mFront != FIRST_FRAME_INDEX))
   {
     ++mFront;
     if(mFront >= mImageUrls.size())
@@ -67,40 +67,24 @@ TextureSet FixedImageCache::Frame(uint32_t frameIndex)
   mFront = frameIndex;
 
   TextureSet textureSet;
-  if(IsFrontReady() == true)
+  if(IsFrontReady())
   {
     textureSet = GetFrontTextureSet();
   }
-  else
-  {
-    mWaitingForReadyFrame = true;
-  }
 
   return textureSet;
 }
 
 TextureSet FixedImageCache::FirstFrame()
 {
-  TextureSet textureSet = GetFrontTextureSet();
-
-  if(!textureSet)
-  {
-    mWaitingForReadyFrame = true;
-  }
-
-  return textureSet;
-}
-
-TextureSet FixedImageCache::NextFrame()
-{
-  TextureSet textureSet = Frame((mFront + 1) % mImageUrls.size());
+  TextureSet textureSet = Frame(FIRST_FRAME_INDEX);
 
   return textureSet;
 }
 
 uint32_t FixedImageCache::GetFrameInterval(uint32_t frameIndex) const
 {
-  return 0u;
+  return mInterval;
 }
 
 int32_t FixedImageCache::GetCurrentFrameIndex() const
@@ -113,6 +97,11 @@ int32_t FixedImageCache::GetTotalFrameCount() const
   return mImageUrls.size();
 }
 
+TextureManager::LoadState FixedImageCache::GetLoadState() const
+{
+  return mLoadStates[mFront];
+}
+
 bool FixedImageCache::IsFrontReady() const
 {
   return (mReadyFlags.size() > 0 && mReadyFlags[mFront] == true);
@@ -121,13 +110,11 @@ bool FixedImageCache::IsFrontReady() const
 void FixedImageCache::LoadBatch()
 {
   // Try and load up to mBatchSize images, until the cache is filled.
-  // Once the cache is filled, mUrlIndex exceeds mImageUrls size and
-  // no more images are loaded.
-  bool frontFrameReady = IsFrontReady();
-
-  for(unsigned int i = 0; i < mBatchSize && mUrlIndex < mImageUrls.size(); ++i)
+  // Once the cache is filled, no more images are loaded.
+  for(unsigned int i = 0; i < mBatchSize && mReadyFlags.size() < mImageUrls.size(); ++i)
   {
-    std::string& url = mImageUrls[mUrlIndex].mUrl;
+    uint32_t frameIndex = mReadyFlags.size();
+    std::string& url = mImageUrls[frameIndex].mUrl;
 
     mReadyFlags.push_back(false);
 
@@ -146,26 +133,44 @@ void FixedImageCache::LoadBatch()
     Dali::ImageDimensions              textureRectSize;
     auto                               preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
 
-    mTextureManager.LoadTexture(
-      url, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, maskInfo, synchronousLoading, mImageUrls[mUrlIndex].mTextureId, textureRect, textureRectSize, atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this, atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply);
+    TextureSet textureSet = mTextureManager.LoadTexture(
+      url, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, maskInfo, synchronousLoading, mImageUrls[frameIndex].mTextureId, textureRect, textureRectSize, atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this, atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply);
 
-    if(loadingStatus == false) // not loading, means it's already ready.
+    // If textureSet is returned but loadingState is false than load state is LOAD_FINISHED. (Notification is not comming yet.)
+    // If textureSet is null and the request is synchronous, load state is LOAD_FAILED.
+    // If textureSet is null but the request is asynchronous, the frame is still loading so load state is LOADING.
+    mLoadStates[frameIndex] = TextureManager::LoadState::LOADING;
+    if(textureSet)
+    {
+      if(!loadingStatus)
+      {
+        SetImageFrameReady(mImageUrls[frameIndex].mTextureId, true);
+      }
+    }
+    else if(synchronousLoading)
     {
-      SetImageFrameReady(mImageUrls[mUrlIndex].mTextureId);
+      // Synchronous loading is failed
+      mLoadStates[frameIndex] = TextureManager::LoadState::LOAD_FAILED;
     }
+
     mRequestingLoad = false;
-    ++mUrlIndex;
   }
-
-  CheckFrontFrame(frontFrameReady);
 }
 
-void FixedImageCache::SetImageFrameReady(TextureManager::TextureId textureId)
+void FixedImageCache::SetImageFrameReady(TextureManager::TextureId textureId, bool loadSuccess)
 {
   for(std::size_t i = 0; i < mImageUrls.size(); ++i)
   {
     if(mImageUrls[i].mTextureId == textureId)
     {
+      if(loadSuccess)
+      {
+        mLoadStates[i] = TextureManager::LoadState::LOAD_FINISHED;
+      }
+      else
+      {
+        mLoadStates[i] = TextureManager::LoadState::LOAD_FAILED;
+      }
       mReadyFlags[i] = true;
       break;
     }
@@ -179,11 +184,24 @@ TextureSet FixedImageCache::GetFrontTextureSet() const
 
 void FixedImageCache::CheckFrontFrame(bool wasReady)
 {
-  if(mWaitingForReadyFrame && wasReady == false && IsFrontReady())
+  if(wasReady == false && IsFrontReady())
+  {
+    mObserver.FrameReady(GetFrontTextureSet(), mInterval);
+  }
+}
+
+void FixedImageCache::ClearCache()
+{
+  if(mTextureManagerAlive)
   {
-    mWaitingForReadyFrame = false;
-    mObserver.FrameReady(GetFrontTextureSet());
+    for(std::size_t i = 0; i < mImageUrls.size(); ++i)
+    {
+      mTextureManager.Remove(mImageUrls[i].mTextureId, this);
+      mImageUrls[i].mTextureId = TextureManager::INVALID_TEXTURE_ID;
+    }
   }
+  mReadyFlags.clear();
+  mLoadStates.assign(mImageUrls.size(), TextureManager::LoadState::NOT_STARTED);
 }
 
 void FixedImageCache::UploadComplete(
@@ -195,31 +213,11 @@ void FixedImageCache::UploadComplete(
   bool           preMultiplied)
 {
   bool frontFrameReady = IsFrontReady();
-
+  SetImageFrameReady(textureId, loadSuccess);
   if(!mRequestingLoad)
   {
-    SetImageFrameReady(textureId);
-
     CheckFrontFrame(frontFrameReady);
   }
-  else
-  {
-    // UploadComplete has been called from within RequestLoad. TextureManager must
-    // therefore already have the texture cached, so make the texture ready.
-    // (Use the last texture, as the texture id hasn't been assigned yet)
-    mReadyFlags.back() = true;
-  }
-}
-
-void FixedImageCache::LoadComplete(
-  bool               loadSuccess,
-  Devel::PixelBuffer pixelBuffer,
-  const VisualUrl&   url,
-  bool               preMultiplied)
-{
-  // LoadComplete is called if this TextureUploadObserver requested to load
-  // an image that will be returned as a type of PixelBuffer by using a method
-  // TextureManager::LoadPixelBuffer.
 }
 
 } //namespace Internal
index 63212df..93a32b6 100644 (file)
@@ -36,6 +36,7 @@ public:
    * @param[in] urlList List of urls to cache
    * @param[in] observer FrameReady observer
    * @param[in] batchSize The size of a batch to load
+   * @param[in] interval Time interval between each frame
    *
    * This will start loading textures immediately, according to the
    * batch and cache sizes. The cache is as large as the number of urls.
@@ -43,73 +44,86 @@ public:
   FixedImageCache(TextureManager&                 textureManager,
                   UrlList&                        urlList,
                   ImageCache::FrameReadyObserver& observer,
-                  unsigned int                    batchSize);
+                  uint32_t                        batchSize,
+                  uint32_t                        interval);
 
   ~FixedImageCache() override;
 
   /**
-   * Get the Nth frame. If it's not ready, this will trigger the
-   * sending of FrameReady() when the image becomes ready.
+   * @copydoc Internal::ImageCache::Frame()
    */
   TextureSet Frame(uint32_t frameIndex) override;
 
   /**
-   * Get the first frame. If it's not ready, this will trigger the
-   * sending of FrameReady() when the image becomes ready.
+   * @copydoc Internal::ImageCache::FirstFrame()
    */
   TextureSet FirstFrame() override;
 
   /**
-   * Get the next frame. If it's not ready, this will trigger the
-   * sending of FrameReady() when the image becomes ready.
-   */
-  TextureSet NextFrame() override;
-
-  /**
-   * Get the interval of Nth frame.
+   * @copydoc Internal::ImageCache::GetFrameInterval()
    */
   uint32_t GetFrameInterval(uint32_t frameIndex) const override;
 
   /**
-   * Get the current rendered frame index.
-   * If there isn't any loaded frame, returns -1.
+   * @copydoc Internal::ImageCache::GetCurrentFrameIndex()
    */
   int32_t GetCurrentFrameIndex() const override;
 
   /**
-   * Get total frame count of the animated image file.
+   * @copydoc Internal::ImageCache::GetTotalFrameCount()
    */
   int32_t GetTotalFrameCount() const override;
 
+  /**
+   * @copydoc Internal::ImageCache::GetLoadState()
+   */
+  TextureManager::LoadState GetLoadState() const override;
+
+  /**
+   * @copydoc Internal::ImageCache::ClearCache()
+   */
+  void ClearCache() override;
+
 private:
   /**
+   * @brief Check whether the front frame is ready or not.
+   *
    * @return true if the front frame is ready
    */
   bool IsFrontReady() const;
 
   /**
-   * Load the next batch of images
+   * @brief Load the next batch of images
    */
   void LoadBatch();
 
   /**
-   * Find the matching image frame, and set it to ready
+   * @brief Find the matching image frame, and set it to ready
+   *
+   * @param[in] textureId texture id to be marked as ready.
+   * @param[in] loadSuccess true if the frame loading is succeeded.
    */
-  void SetImageFrameReady(TextureManager::TextureId textureId);
+  void SetImageFrameReady(TextureManager::TextureId textureId, bool loadSuccess);
 
   /**
-   * Get the texture set of the front frame.
-   * @return the texture set
+   * @brief Get the texture set of the front frame.
+   *
+   * @return the texture set of the front of Cache.
    */
   TextureSet GetFrontTextureSet() const;
 
   /**
-   * Check if the front frame has become ready - if so, inform observer
+   * @brief Check if the front frame has become ready - if so, inform observer
+   *
    * @param[in] wasReady Readiness before call.
    */
   void CheckFrontFrame(bool wasReady);
 
 protected:
+
+  /**
+   * @copydoc Toolkit::TextureUploadObserver::UploadComplete()
+   */
   void UploadComplete(
     bool           loadSuccess,
     int32_t        textureId,
@@ -118,16 +132,11 @@ protected:
     const Vector4& atlasRect,
     bool           premultiplied) override;
 
-  void LoadComplete(
-    bool               loadSuccess,
-    Devel::PixelBuffer pixelBuffer,
-    const VisualUrl&   url,
-    bool               preMultiplied) override;
-
 private:
-  std::vector<UrlStore>& mImageUrls;
-  std::vector<bool>      mReadyFlags;
-  unsigned int           mFront;
+  std::vector<UrlStore>&                 mImageUrls;
+  std::vector<bool>                      mReadyFlags;
+  std::vector<TextureManager::LoadState> mLoadStates;
+  uint32_t                               mFront;
 };
 
 } //namespace Internal
index cccb085..dcd0d40 100644 (file)
@@ -24,12 +24,12 @@ namespace Internal
 {
 ImageCache::ImageCache(TextureManager&                 textureManager,
                        ImageCache::FrameReadyObserver& observer,
-                       unsigned int                    batchSize)
+                       uint32_t                        batchSize,
+                       uint32_t                        interval)
 : mTextureManager(textureManager),
   mObserver(observer),
   mBatchSize(batchSize),
-  mUrlIndex(0u),
-  mWaitingForReadyFrame(false),
+  mInterval(interval),
   mRequestingLoad(false),
   mTextureManagerAlive(true)
 {
@@ -49,6 +49,11 @@ void ImageCache::TextureManagerDestroyed()
   mTextureManagerAlive = false;
 }
 
+void ImageCache::SetInterval(uint32_t interval)
+{
+  mInterval = interval;
+}
+
 } //namespace Internal
 } //namespace Toolkit
 } //namespace Dali
index f21d707..432ad8c 100644 (file)
@@ -37,10 +37,11 @@ public:
   {
   public:
     /**
-     * Informs observer when the next texture set is ready to display
+     * @brief Informs observer when the next texture set is ready to display
      * @param[in] textureSet The ready texture set
+     * @param[in] interval interval for the frame
      */
-    virtual void FrameReady(TextureSet textureSet) = 0;
+    virtual void FrameReady(TextureSet textureSet, uint32_t interval) = 0;
   };
 
   struct UrlStore
@@ -56,67 +57,93 @@ public:
 
 public:
   /**
-   * Constructor.
+   * @brief Constructor.
    * @param[in] textureManager The texture manager
    * @param[in] urlList List of urls to cache
    * @param[in] observer FrameReady observer
    * @param[in] batchSize The size of a batch to load
+   * @param[in] interval Time interval between each frame
    *
    * This will start loading textures immediately, according to the
    * batch and cache sizes. The cache is as large as the number of urls.
    */
   ImageCache(TextureManager&                 textureManager,
              ImageCache::FrameReadyObserver& observer,
-             unsigned int                    batchSize);
+             uint32_t                        batchSize,
+             uint32_t                        interval);
 
   virtual ~ImageCache();
 
   /**
-   * Get the first frame. If it's not ready, this will trigger the
+   * @brief Get the first frame. If it's not ready, this will trigger the
    * sending of FrameReady() when the image becomes ready.
+   *
+   * @return TextureSet of the first frame.
    */
   virtual TextureSet FirstFrame() = 0;
 
   /**
-   * Get the next frame. If it's not ready, this will trigger the
-   * sending of FrameReady() when the image becomes ready.
-   */
-  virtual TextureSet NextFrame() = 0;
-
-  /**
-   * Get the Nth frame. If it's not ready, this will trigger the
+   * @brief Get the Nth frame. If it's not ready, this will trigger the
    * sending of FrameReady() when the image becomes ready.
+   *
+   * @param[in] frameIndex required frame index to be returned.
+   * @return TextureSet of the frame index.
    */
   virtual TextureSet Frame(uint32_t frameIndex) = 0;
 
   /**
-   * Get the interval of Nth frame.
+   * @brief Get the interval of Nth frame.
+   *
+   * @param[in] frameIndex frame index to get frame interval.
+   * @return Time interval in millisecond between frames of frameIndex and frameIndex + 1.
    */
   virtual uint32_t GetFrameInterval(uint32_t frameIndex) const = 0;
 
   /**
-   * Get the current rendered frame index.
+   * @brief Get the current rendered frame index.
    * If there isn't any loaded frame, returns -1.
+   *
+   * @return Frame index of currently showing frame.
    */
   virtual int32_t GetCurrentFrameIndex() const = 0;
 
   /**
-   * Get total frame count of the animated image file.
+   * @brief Get total frame count of the animated image file.
+   *
+   * @return Total frame count of the animated image file.
    */
   virtual int32_t GetTotalFrameCount() const = 0;
 
+  /**
+   * @brief Get Loading state of the animated image file.
+   *
+   * @return LoadState of currently requested frame.
+   */
+  virtual TextureManager::LoadState GetLoadState() const = 0;
+
+  /**
+   * @brief Clears animated image cache and remove loaded textures.
+   */
+  virtual void ClearCache() = 0;
+
+  /**
+   * @brief Set default interval between each frame.
+   *
+   * @param[in] interval time interval in millisecond to be used as default interval.
+   */
+  virtual void SetInterval(uint32_t interval);
+
 private:
   /**
-   * Called before the texture manager is destroyed.
+   * @brief Called before the texture manager is destroyed.
    */
   void TextureManagerDestroyed() final;
 
 protected:
   TextureManager&     mTextureManager;
   FrameReadyObserver& mObserver;
-  unsigned int        mBatchSize;
-  unsigned int        mUrlIndex;
-  bool                mWaitingForReadyFrame : 1;
+  uint32_t            mBatchSize;
+  uint32_t            mInterval;
   bool                mRequestingLoad : 1;
   bool                mTextureManagerAlive : 1;
 };
index eba9341..f8f8310 100644 (file)
@@ -17,8 +17,6 @@
 // CLASS HEADER
 #include "rolling-animated-image-cache.h"
 
-// EXTERNAL HEADERS
-
 // INTERNAL HEADERS
 #include <dali-toolkit/devel-api/image-loader/texture-manager.h>
 #include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
@@ -45,7 +43,7 @@ Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "
 #define LOG_CACHE
 #endif
 
-const bool ENABLE_ORIENTATION_CORRECTION(true);
+static constexpr bool ENABLE_ORIENTATION_CORRECTION(true);
 
 } // namespace
 
@@ -55,32 +53,31 @@ namespace Toolkit
 {
 namespace Internal
 {
+namespace
+{
+static constexpr uint32_t SINGLE_IMAGE_COUNT = 1u;
+static constexpr uint32_t FIRST_FRAME_INDEX  = 0u;
+} // namespace
+
 RollingAnimatedImageCache::RollingAnimatedImageCache(
-  TextureManager& textureManager, AnimatedImageLoading& animatedImageLoading, uint32_t frameCount, ImageCache::FrameReadyObserver& observer, uint16_t cacheSize, uint16_t batchSize, bool isSynchronousLoading)
-: ImageCache(textureManager, observer, batchSize),
+  TextureManager& textureManager, AnimatedImageLoading& animatedImageLoading, ImageCache::FrameReadyObserver& observer, uint16_t cacheSize, uint16_t batchSize, bool isSynchronousLoading)
+: ImageCache(textureManager, observer, batchSize, 0u),
   mAnimatedImageLoading(animatedImageLoading),
-  mFrameCount(frameCount),
-  mFrameIndex(0),
+  mFrameCount(SINGLE_IMAGE_COUNT),
+  mFrameIndex(FIRST_FRAME_INDEX),
   mCacheSize(cacheSize),
   mQueue(cacheSize),
-  mIsSynchronousLoading(isSynchronousLoading),
-  mOnLoading(false)
+  mLoadState(TextureManager::LoadState::NOT_STARTED),
+  mIsSynchronousLoading(isSynchronousLoading)
 {
   mImageUrls.resize(mFrameCount);
   mIntervals.assign(mFrameCount, 0);
-  LoadBatch();
 }
 
 RollingAnimatedImageCache::~RollingAnimatedImageCache()
 {
-  if(mTextureManagerAlive)
-  {
-    while(!mQueue.IsEmpty())
-    {
-      ImageFrame imageFrame = mQueue.PopFront();
-      mTextureManager.Remove(mImageUrls[imageFrame.mFrameNumber].mTextureId, this);
-    }
-  }
+  ClearCache();
+  mAnimatedImageLoading.Reset();
 }
 
 TextureSet RollingAnimatedImageCache::Frame(uint32_t frameIndex)
@@ -95,13 +92,13 @@ TextureSet RollingAnimatedImageCache::Frame(uint32_t frameIndex)
   }
 
   TextureSet textureSet;
+  uint32_t batchFrameIndex = frameIndex;
   // If we need to load new frame that are not stored in queue.
   // Load the frame synchronously.
   if(mIsSynchronousLoading && mQueue.IsEmpty())
   {
-    bool synchronousLoading = true;
-    textureSet              = mTextureManager.LoadAnimatedImageTexture(mAnimatedImageLoading, frameIndex, SamplingMode::BOX_THEN_LINEAR, synchronousLoading, mImageUrls[frameIndex].mTextureId, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this);
-    mFrameIndex             = (frameIndex + 1) % mFrameCount;
+    textureSet  = RequestFrameLoading(frameIndex, frameIndex == FIRST_FRAME_INDEX, true);
+    batchFrameIndex = (frameIndex + 1) % mFrameCount;
   }
 
   if(popExist || mQueue.IsEmpty())
@@ -111,25 +108,24 @@ TextureSet RollingAnimatedImageCache::Frame(uint32_t frameIndex)
     {
       if(!mLoadWaitingQueue.empty())
       {
-        mFrameIndex = (mLoadWaitingQueue.back() + 1) % mFrameCount;
+        batchFrameIndex = (mLoadWaitingQueue.back() + 1) % mFrameCount;
       }
       else
       {
-        mFrameIndex = (mQueue.Back().mFrameNumber + 1) % mFrameCount;
+        batchFrameIndex = (mQueue.Back().mFrameNumber + 1) % mFrameCount;
       }
     }
     else
     {
-      mOnLoading = false;
       // If the request is for the first frame or a jumped frame(JUMP_TO) remove current waiting queue.
       mLoadWaitingQueue.clear();
       // If the queue is empty, and the frame of frameIndex is not loaded synchronously. load batch from the frame of frameIndex
       if(!textureSet)
       {
-        mFrameIndex = frameIndex;
+        batchFrameIndex = frameIndex;
       }
     }
-    LoadBatch();
+    LoadBatch(batchFrameIndex);
   }
 
   if(!textureSet)
@@ -138,10 +134,6 @@ TextureSet RollingAnimatedImageCache::Frame(uint32_t frameIndex)
     {
       textureSet = GetFrontTextureSet();
     }
-    else
-    {
-      mWaitingForReadyFrame = true;
-    }
   }
 
   return textureSet;
@@ -149,32 +141,17 @@ TextureSet RollingAnimatedImageCache::Frame(uint32_t frameIndex)
 
 TextureSet RollingAnimatedImageCache::FirstFrame()
 {
-  return Frame(0u);
-}
-
-TextureSet RollingAnimatedImageCache::NextFrame()
-{
-  TextureSet textureSet;
-  if(!mQueue.IsEmpty())
-  {
-    uint32_t frameIndex = mQueue.Front().mFrameNumber;
-    if(IsFrontReady())
-    {
-      frameIndex = (frameIndex + 1) % mFrameCount;
-    }
-    textureSet = Frame(frameIndex);
-  }
-  else
-  {
-    DALI_LOG_ERROR("Cache is empty.");
-  }
-
+  TextureSet textureSet = Frame(FIRST_FRAME_INDEX);
   return textureSet;
 }
 
 uint32_t RollingAnimatedImageCache::GetFrameInterval(uint32_t frameIndex) const
 {
-  return mAnimatedImageLoading.GetFrameInterval(frameIndex);
+  if(frameIndex >= mIntervals.size())
+  {
+    return 0u;
+  }
+  return mIntervals[frameIndex];
 }
 
 int32_t RollingAnimatedImageCache::GetCurrentFrameIndex() const
@@ -191,12 +168,17 @@ int32_t RollingAnimatedImageCache::GetTotalFrameCount() const
   return mFrameCount;
 }
 
+TextureManager::LoadState RollingAnimatedImageCache::GetLoadState() const
+{
+  return mLoadState;
+}
+
 bool RollingAnimatedImageCache::IsFrontReady() const
 {
   return (!mQueue.IsEmpty() && mQueue.Front().mReady);
 }
 
-void RollingAnimatedImageCache::RequestFrameLoading(uint32_t frameIndex)
+TextureSet RollingAnimatedImageCache::RequestFrameLoading(uint32_t frameIndex, bool useCache, bool synchronousLoading)
 {
   ImageFrame imageFrame;
   imageFrame.mFrameNumber = frameIndex;
@@ -204,39 +186,59 @@ void RollingAnimatedImageCache::RequestFrameLoading(uint32_t frameIndex)
 
   mQueue.PushBack(imageFrame);
 
-  mRequestingLoad = true;
-
-  bool synchronousLoading = false;
-  mTextureManager.LoadAnimatedImageTexture(mAnimatedImageLoading, frameIndex, SamplingMode::BOX_THEN_LINEAR, synchronousLoading, mImageUrls[frameIndex].mTextureId, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this);
+  bool       loadingStatus = false;
+  TextureSet textureSet    = mTextureManager.LoadAnimatedImageTexture(mAnimatedImageLoading,
+                                                                   frameIndex,
+                                                                   loadingStatus,
+                                                                   mImageUrls[frameIndex].mTextureId,
+                                                                   SamplingMode::BOX_THEN_LINEAR,
+                                                                   Dali::WrapMode::Type::DEFAULT,
+                                                                   Dali::WrapMode::Type::DEFAULT,
+                                                                   synchronousLoading,
+                                                                   useCache,
+                                                                   this);
+
+  // If textureSet is returned but loadingState is false than load state is LOAD_FINISHED. (Notification is not comming yet.)
+  // If textureSet is null and the request is synchronous, load state is LOAD_FAILED.
+  // If textureSet is null but the request is asynchronous, the frame is still loading so load state is LOADING.
+  mLoadState = TextureManager::LoadState::LOADING;
+  if(textureSet)
+  {
+    if(!loadingStatus)
+    {
+      mLoadState = TextureManager::LoadState::LOAD_FINISHED;
+    }
+  }
+  else if(synchronousLoading)
+  {
+    // Synchronous loading is failed
+    mLoadState = TextureManager::LoadState::LOAD_FAILED;
+  }
 
-  mRequestingLoad = false;
+  return textureSet;
 }
 
-void RollingAnimatedImageCache::LoadBatch()
+void RollingAnimatedImageCache::LoadBatch(uint32_t frameIndex)
 {
   // Try and load up to mBatchSize images, until the cache is filled.
   // Once the cache is filled, as frames progress, the old frame is
   // removed, and another frame is loaded
-
-  bool frontFrameReady = IsFrontReady();
-  for(unsigned int i = 0; i < mBatchSize && mQueue.Count() + mLoadWaitingQueue.size() < static_cast<uint32_t>(mCacheSize) && !mQueue.IsFull(); ++i)
+  uint32_t minimumSize = std::min(mCacheSize, mFrameCount);
+  for(uint32_t i = 0; i < mBatchSize && (mQueue.Count() + mLoadWaitingQueue.size()) < minimumSize; ++i)
   {
-    if(!mOnLoading)
+    if(mLoadState != TextureManager::LoadState::LOADING)
     {
-      mOnLoading = true;
-      RequestFrameLoading(mFrameIndex);
+      RequestFrameLoading(frameIndex, frameIndex == FIRST_FRAME_INDEX, false);
     }
     else
     {
-      mLoadWaitingQueue.push_back(mFrameIndex);
+      mLoadWaitingQueue.push_back(frameIndex);
     }
 
-    mFrameIndex++;
-    mFrameIndex %= mFrameCount;
+    frameIndex++;
+    frameIndex %= mFrameCount;
   }
 
-  CheckFrontFrame(frontFrameReady);
-
   LOG_CACHE;
 }
 
@@ -265,43 +267,53 @@ TextureManager::TextureId RollingAnimatedImageCache::GetCachedTextureId(int inde
   return mImageUrls[mQueue[index].mFrameNumber].mTextureId;
 }
 
-void RollingAnimatedImageCache::CheckFrontFrame(bool wasReady)
+void RollingAnimatedImageCache::ClearCache()
 {
-  if(mWaitingForReadyFrame && wasReady == false && IsFrontReady())
+  while(mTextureManagerAlive && !mQueue.IsEmpty())
   {
-    mWaitingForReadyFrame = false;
-    mObserver.FrameReady(GetFrontTextureSet());
+    ImageFrame imageFrame = mQueue.PopFront();
+    mTextureManager.Remove(mImageUrls[imageFrame.mFrameNumber].mTextureId, this);
+    mImageUrls[imageFrame.mFrameNumber].mTextureId = TextureManager::INVALID_TEXTURE_ID;
   }
+
+  mLoadWaitingQueue.clear();
+  mLoadState = TextureManager::LoadState::NOT_STARTED;
 }
 
-void RollingAnimatedImageCache::UploadComplete(
-  bool           loadSuccess,
-  int32_t        textureId,
-  TextureSet     textureSet,
-  bool           useAtlasing,
-  const Vector4& atlasRect,
-  bool           preMultiplied)
+void RollingAnimatedImageCache::AnimatedImageUploadComplete(bool loadSuccess, int32_t textureId, uint32_t frameCount, uint32_t interval)
 {
   DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::UploadComplete(textureId:%d) start\n", textureId);
   LOG_CACHE;
 
-  bool frontFrameReady = IsFrontReady();
-
-  if(!mRequestingLoad)
+  // Reset size of Queue according to the real frame count.
+  if(mFrameCount != frameCount)
   {
-    SetImageFrameReady(textureId);
+    mFrameCount = frameCount;
+    mImageUrls.resize(mFrameCount);
+    mIntervals.assign(mFrameCount, 0u);
+  }
 
-    CheckFrontFrame(frontFrameReady);
+  if(loadSuccess)
+  {
+    mLoadState = TextureManager::LoadState::LOAD_FINISHED;
   }
   else
   {
-    // UploadComplete has been called from within RequestLoad. TextureManager must
-    // therefore already have the texture cached, so make the texture ready.
-    // (Use the last texture, as the texture id hasn't been assigned yet)
-    mQueue.Back().mReady = true;
+    mLoadState = TextureManager::LoadState::LOAD_FAILED;
+  }
+
+  bool frontFrameReady = IsFrontReady();
+  // Because only one frame is on loading and the others are in mLoadWaitingQueue,
+  // mQueue.Back() is always the frame currently loaded.
+  mQueue.Back().mReady = true;
+  mIntervals[mQueue.Back().mFrameNumber] = interval;
+  // Check whether currently loaded frame is front of queue or not.
+  // If it is, notify frame ready to observer.
+  if(frontFrameReady == false && IsFrontReady())
+  {
+    mObserver.FrameReady(GetFrontTextureSet(), interval);
   }
 
-  mOnLoading = false;
   // The frames of a single animated image can not be loaded parallelly.
   // Therefore, a frame is now loading, other orders are waiting.
   // And, after the frame is loaded, requests load of next order.
@@ -309,24 +321,27 @@ void RollingAnimatedImageCache::UploadComplete(
   {
     uint32_t loadingIndex = mLoadWaitingQueue.front();
     mLoadWaitingQueue.erase(mLoadWaitingQueue.begin());
-    mOnLoading = true;
-    RequestFrameLoading(loadingIndex);
+    RequestFrameLoading(loadingIndex, loadingIndex == FIRST_FRAME_INDEX, false);
+  }
+  else if(mQueue.Count() == 1u && frameCount > SINGLE_IMAGE_COUNT)
+  {
+    // There is only an image in queue and no waiting queue.
+    // Request to load batch once again.
+    uint32_t batchFrameIndex = 0u;
+    if(!mLoadWaitingQueue.empty())
+    {
+      batchFrameIndex = (mLoadWaitingQueue.back() + 1) % mFrameCount;
+    }
+    else
+    {
+      batchFrameIndex = (mQueue.Back().mFrameNumber + 1) % mFrameCount;
+    }
+    LoadBatch(batchFrameIndex);
   }
 
   LOG_CACHE;
 }
 
-void RollingAnimatedImageCache::LoadComplete(
-  bool               loadSuccess,
-  Devel::PixelBuffer pixelBuffer,
-  const VisualUrl&   url,
-  bool               preMultiplied)
-{
-  // LoadComplete is called if this TextureUploadObserver requested to load
-  // an image that will be returned as a type of PixelBuffer by using a method
-  // TextureManager::LoadPixelBuffer.
-}
-
-} //namespace Internal
+} // namespace Internal
 } //namespace Toolkit
 } //namespace Dali
index b1b4afc..6a06717 100644 (file)
@@ -40,10 +40,9 @@ class RollingAnimatedImageCache : public ImageCache, public TextureUploadObserve
 {
 public:
   /**
-   * Constructor.
+   * @brief Constructor.
    * @param[in] textureManager The texture manager
    * @param[in] animatedImageLoader The loaded animated image
-   * @param[in] frameCount The number of frames in the animated image
    * @param[in] observer FrameReady observer
    * @param[in] cacheSize The size of the cache
    * @param[in] batchSize The size of a batch to load
@@ -54,124 +53,124 @@ public:
    */
   RollingAnimatedImageCache(TextureManager&                 textureManager,
                             AnimatedImageLoading&           animatedImageLoader,
-                            uint32_t                        frameCount,
                             ImageCache::FrameReadyObserver& observer,
                             uint16_t                        cacheSize,
                             uint16_t                        batchSize,
                             bool                            isSynchronousLoading);
 
   /**
-   * Destructor
+   * @brief Destructor
    */
   ~RollingAnimatedImageCache() override;
 
   /**
-   * Get the Nth frame. If it's not ready, this will trigger the
-   * sending of FrameReady() when the image becomes ready.
+   * @copydoc Internal::ImageCache::Frame()
    */
   TextureSet Frame(uint32_t frameIndex) override;
 
   /**
-   * Get the first frame. If it's not ready, this will trigger the
-   * sending of FrameReady() when the image becomes ready.
+   * @copydoc Internal::ImageCache::FirstFrame()
    */
   TextureSet FirstFrame() override;
 
   /**
-   * Get the next frame. If it's not ready, this will trigger the
-   * sending of FrameReady() when the image becomes ready.
-   */
-  TextureSet NextFrame() override;
-
-  /**
-   * Get the interval of Nth frame.
+   * @copydoc Internal::ImageCache::GetFrameInterval()
    */
   uint32_t GetFrameInterval(uint32_t frameIndex) const override;
 
   /**
-   * Get the current rendered frame index.
-   * If there isn't any loaded frame, returns -1.
+   * @copydoc Internal::ImageCache::GetCurrentFrameIndex()
    */
   int32_t GetCurrentFrameIndex() const override;
 
   /**
-   * Get total frame count of the animated image file.
+   * @copydoc Internal::ImageCache::GetTotalFrameCount()
    */
   int32_t GetTotalFrameCount() const override;
 
+  /**
+   * @copydoc Internal::ImageCache::GetLoadState()
+   */
+  TextureManager::LoadState GetLoadState() const override;
+
+  /**
+   * @copydoc Internal::ImageCache::ClearCache()
+   */
+  void ClearCache() override;
+
 private:
   /**
+   * @brief Check whether the front frame is ready or not.
+   *
    * @return true if the front frame is ready
    */
   bool IsFrontReady() const;
 
   /**
-   * Request to Load a frame
+   * @brief Request to Load a frame
+   *
+   * @param[in] frameIndex          index of frame to be loaded.
+   * @param[in] useCache            true if this frame loading uses cache.
+   * @param[in] synchronousLoading  true if the frame should be loaded synchronously
    */
-  void RequestFrameLoading(uint32_t frameIndex);
+  TextureSet RequestFrameLoading(uint32_t frameIndex, bool useCache, bool synchronousLoading);
 
   /**
-   * Load the next batch of images
+   * @brief Load the next batch of images
+   *
+   * @param[in] frameIndex starting frame index of batch to be loaded.
    */
-  void LoadBatch();
+  void LoadBatch(uint32_t frameIndex);
 
   /**
-   * Find the matching image frame, and set it to ready
+   * @brief Find the matching image frame, and set it to ready
+   *
+   * @param[in] textureId texture id to be marked as ready.
    */
   void SetImageFrameReady(TextureManager::TextureId textureId);
 
   /**
-   * Get the texture set of the front frame.
-   * @return the texture set
+   * @brief Get the texture set of the front frame.
+   *
+   * @return the texture set of the front of Cache.
    */
   TextureSet GetFrontTextureSet() const;
 
   /**
-   * Get the texture id of the given index
+   * @brief Get the texture id of the given index
+   *
+   * @param[in] index index of the queue.
    */
   TextureManager::TextureId GetCachedTextureId(int index) const;
 
+protected:
+
   /**
-   * Check if the front frame has become ready - if so, inform observer
-   * @param[in] wasReady Readiness before call.
+   * @copydoc Toolkit::TextureUploadObserver::AnimatedImageUploadComplete()
    */
-  void CheckFrontFrame(bool wasReady);
-
-protected:
-  void UploadComplete(
-    bool           loadSuccess,
-    int32_t        textureId,
-    TextureSet     textureSet,
-    bool           useAtlasing,
-    const Vector4& atlasRect,
-    bool           preMultiplied) override;
-
-  void LoadComplete(
-    bool               loadSuccess,
-    Devel::PixelBuffer pixelBuffer,
-    const VisualUrl&   url,
-    bool               preMultiplied) override;
+  void AnimatedImageUploadComplete(bool loadSuccess, int32_t textureId, uint32_t frameCount, uint32_t interval) override;
 
 private:
+
   /**
    * Secondary class to hold readiness and index into url
    */
   struct ImageFrame
   {
-    unsigned int mFrameNumber = 0u;
-    bool         mReady       = false;
+    uint32_t mFrameNumber = 0u;
+    bool     mReady       = false;
   };
 
   Dali::AnimatedImageLoading mAnimatedImageLoading;
   uint32_t                   mFrameCount;
-  int                        mFrameIndex;
-  int                        mCacheSize;
+  uint32_t                   mFrameIndex;
+  uint32_t                   mCacheSize;
   std::vector<UrlStore>      mImageUrls;
   std::vector<int32_t>       mIntervals;
   std::vector<uint32_t>      mLoadWaitingQueue;
   CircularQueue<ImageFrame>  mQueue;
+  TextureManager::LoadState  mLoadState; ///< The texture loading state
   bool                       mIsSynchronousLoading;
-  bool                       mOnLoading;
 };
 
 } // namespace Internal
index 9bcf8e4..c776605 100644 (file)
@@ -44,7 +44,9 @@ Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "
 #define LOG_CACHE
 #endif
 
-const bool ENABLE_ORIENTATION_CORRECTION(true);
+static constexpr bool ENABLE_ORIENTATION_CORRECTION(true);
+
+static constexpr uint32_t FIRST_FRAME_INDEX = 0u;
 
 } // namespace
 
@@ -55,57 +57,39 @@ namespace Toolkit
 namespace Internal
 {
 RollingImageCache::RollingImageCache(
-  TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer, uint16_t cacheSize, uint16_t batchSize)
-: ImageCache(textureManager, observer, batchSize),
+  TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer, uint16_t cacheSize, uint16_t batchSize, uint32_t interval)
+: ImageCache(textureManager, observer, batchSize, interval),
   mImageUrls(urlList),
   mQueue(cacheSize)
 {
-  LoadBatch();
+  mLoadStates.assign(mImageUrls.size(), TextureManager::LoadState::NOT_STARTED);
 }
 
 RollingImageCache::~RollingImageCache()
 {
-  if(mTextureManagerAlive)
-  {
-    while(!mQueue.IsEmpty())
-    {
-      ImageFrame imageFrame = mQueue.PopFront();
-      mTextureManager.Remove(mImageUrls[imageFrame.mUrlIndex].mTextureId, this);
-    }
-  }
+  ClearCache();
 }
 
 TextureSet RollingImageCache::Frame(uint32_t frameIndex)
 {
-  // If a frame of frameIndex is not loaded, clear the queue and remove all loaded textures.
-  if(mImageUrls[frameIndex].mTextureId == TextureManager::INVALID_TEXTURE_ID)
+  // Pop frames until the frame of frameIndex become front frame.
+  bool popExist = false;
+  while(!mQueue.IsEmpty() && mQueue.Front().mUrlIndex != frameIndex)
   {
-    mUrlIndex = frameIndex;
-    while(!mQueue.IsEmpty())
-    {
-      ImageFrame imageFrame = mQueue.PopFront();
-      mTextureManager.Remove(mImageUrls[imageFrame.mUrlIndex].mTextureId, this);
-      mImageUrls[imageFrame.mUrlIndex].mTextureId = TextureManager::INVALID_TEXTURE_ID;
-    }
-    LoadBatch();
+    ImageFrame imageFrame = mQueue.PopFront();
+    mTextureManager.Remove(mImageUrls[imageFrame.mUrlIndex].mTextureId, this);
+    mImageUrls[imageFrame.mUrlIndex].mTextureId = TextureManager::INVALID_TEXTURE_ID;
+    popExist                                    = true;
   }
-  // If the frame is already loaded, remove previous frames of the frame in the queue
-  // and load new frames amount of removed frames.
-  else
+  if(popExist || mQueue.IsEmpty())
   {
-    bool popExist = false;
-    while(!mQueue.IsEmpty() && mQueue.Front().mUrlIndex != frameIndex)
-    {
-      ImageFrame imageFrame = mQueue.PopFront();
-      mTextureManager.Remove(mImageUrls[imageFrame.mUrlIndex].mTextureId, this);
-      mImageUrls[imageFrame.mUrlIndex].mTextureId = TextureManager::INVALID_TEXTURE_ID;
-      popExist                                    = true;
-    }
-    if(popExist)
+    uint32_t batchFrameIndex = frameIndex;
+    // If the frame of frameIndex was already loaded, load batch from the last frame of queue
+    if(!mQueue.IsEmpty())
     {
-      mUrlIndex = (mQueue.Back().mUrlIndex + 1) % mImageUrls.size();
-      LoadBatch();
+      batchFrameIndex = (mQueue.Back().mUrlIndex + 1) % mImageUrls.size();
     }
+    LoadBatch(batchFrameIndex);
   }
 
   TextureSet textureSet;
@@ -113,42 +97,19 @@ TextureSet RollingImageCache::Frame(uint32_t frameIndex)
   {
     textureSet = GetFrontTextureSet();
   }
-  else
-  {
-    mWaitingForReadyFrame = true;
-  }
 
   return textureSet;
 }
 
 TextureSet RollingImageCache::FirstFrame()
 {
-  return Frame(0u);
-}
-
-TextureSet RollingImageCache::NextFrame()
-{
-  TextureSet textureSet;
-  if(!mQueue.IsEmpty())
-  {
-    uint32_t frameIndex = mQueue.Front().mUrlIndex;
-    if(IsFrontReady())
-    {
-      frameIndex = (frameIndex + 1) % mImageUrls.size();
-    }
-    textureSet = Frame(frameIndex);
-  }
-  else
-  {
-    DALI_LOG_ERROR("Cache is empty.");
-  }
-
+  TextureSet textureSet = Frame(FIRST_FRAME_INDEX);
   return textureSet;
 }
 
 uint32_t RollingImageCache::GetFrameInterval(uint32_t frameIndex) const
 {
-  return 0u;
+  return mInterval;
 }
 
 int32_t RollingImageCache::GetCurrentFrameIndex() const
@@ -165,29 +126,29 @@ int32_t RollingImageCache::GetTotalFrameCount() const
   return mImageUrls.size();
 }
 
+TextureManager::LoadState RollingImageCache::GetLoadState() const
+{
+  return mLoadStates[mQueue.Front().mUrlIndex];
+}
+
 bool RollingImageCache::IsFrontReady() const
 {
   return (!mQueue.IsEmpty() && mQueue.Front().mReady);
 }
 
-void RollingImageCache::LoadBatch()
+void RollingImageCache::LoadBatch(uint32_t frameIndex)
 {
   // Try and load up to mBatchSize images, until the cache is filled.
   // Once the cache is filled, as frames progress, the old frame is
   // cleared, but not erased, and another image is loaded
-  bool frontFrameReady = IsFrontReady();
-
   for(unsigned int i = 0; i < mBatchSize && !mQueue.IsFull(); ++i)
   {
     ImageFrame imageFrame;
 
-    std::string& url     = mImageUrls[mUrlIndex].mUrl;
-    imageFrame.mUrlIndex = mUrlIndex;
+    std::string& url     = mImageUrls[frameIndex].mUrl;
+    imageFrame.mUrlIndex = frameIndex;
     imageFrame.mReady    = false;
 
-    ++mUrlIndex;
-    mUrlIndex %= mImageUrls.size();
-
     mQueue.PushBack(imageFrame);
 
     // Note, if the image is already loaded, then UploadComplete will get called
@@ -205,21 +166,47 @@ void RollingImageCache::LoadBatch()
     Dali::ImageDimensions              textureRectSize;
     auto                               preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
 
-    mTextureManager.LoadTexture(
+    TextureSet textureSet = mTextureManager.LoadTexture(
       url, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, maskInfo, synchronousLoading, mImageUrls[imageFrame.mUrlIndex].mTextureId, textureRect, textureRectSize, atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this, atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply);
 
+    // If textureSet is returned but loadingState is false than load state is LOAD_FINISHED. (Notification is not comming yet.)
+    // If textureSet is null and the request is synchronous, load state is LOAD_FAILED.
+    // If textureSet is null but the request is asynchronous, the frame is still loading so load state is LOADING.
+    mLoadStates[frameIndex] = TextureManager::LoadState::LOADING;
+    if(textureSet)
+    {
+      if(!loadingStatus)
+      {
+        mLoadStates[frameIndex] = TextureManager::LoadState::LOAD_FINISHED;
+      }
+    }
+    else if(synchronousLoading)
+    {
+      // Synchronous loading is failed
+      mLoadStates[frameIndex] = TextureManager::LoadState::LOAD_FAILED;
+    }
+
     mRequestingLoad = false;
-  }
 
-  CheckFrontFrame(frontFrameReady);
+    ++frameIndex;
+    frameIndex %= mImageUrls.size();
+  }
 }
 
-void RollingImageCache::SetImageFrameReady(TextureManager::TextureId textureId)
+void RollingImageCache::SetImageFrameReady(TextureManager::TextureId textureId, bool loadSuccess)
 {
   for(std::size_t i = 0; i < mQueue.Count(); ++i)
   {
     if(GetCachedTextureId(i) == textureId)
     {
+      if(loadSuccess)
+      {
+        mLoadStates[i] = TextureManager::LoadState::LOAD_FINISHED;
+      }
+      else
+      {
+        mLoadStates[i] = TextureManager::LoadState::LOAD_FAILED;
+      }
       mQueue[i].mReady = true;
       break;
     }
@@ -239,13 +226,23 @@ TextureManager::TextureId RollingImageCache::GetCachedTextureId(int index) const
 
 void RollingImageCache::CheckFrontFrame(bool wasReady)
 {
-  if(mWaitingForReadyFrame && wasReady == false && IsFrontReady())
+  if(wasReady == false && IsFrontReady())
   {
-    mWaitingForReadyFrame = false;
-    mObserver.FrameReady(GetFrontTextureSet());
+    mObserver.FrameReady(GetFrontTextureSet(), mInterval);
   }
 }
 
+void RollingImageCache::ClearCache()
+{
+  while(mTextureManagerAlive && !mQueue.IsEmpty())
+  {
+    ImageFrame imageFrame = mQueue.PopFront();
+    mTextureManager.Remove(mImageUrls[imageFrame.mUrlIndex].mTextureId, this);
+    mImageUrls[imageFrame.mUrlIndex].mTextureId = TextureManager::INVALID_TEXTURE_ID;
+  }
+  mLoadStates.assign(mImageUrls.size(), TextureManager::LoadState::NOT_STARTED);
+}
+
 void RollingImageCache::UploadComplete(
   bool           loadSuccess,
   int32_t        textureId,
@@ -258,35 +255,15 @@ void RollingImageCache::UploadComplete(
   LOG_CACHE;
 
   bool frontFrameReady = IsFrontReady();
-
+  SetImageFrameReady(textureId, loadSuccess);
   if(!mRequestingLoad)
   {
-    SetImageFrameReady(textureId);
-
     CheckFrontFrame(frontFrameReady);
   }
-  else
-  {
-    // UploadComplete has been called from within RequestLoad. TextureManager must
-    // therefore already have the texture cached, so make the texture ready.
-    // (Use the last texture, as the texture id hasn't been assigned yet)
-    mQueue.Back().mReady = true;
-  }
 
   LOG_CACHE;
 }
 
-void RollingImageCache::LoadComplete(
-  bool               loadSuccess,
-  Devel::PixelBuffer pixelBuffer,
-  const VisualUrl&   url,
-  bool               preMultiplied)
-{
-  // LoadComplete is called if this TextureUploadObserver requested to load
-  // an image that will be returned as a type of PixelBuffer by using a method
-  // TextureManager::LoadPixelBuffer.
-}
-
 } //namespace Internal
 } //namespace Toolkit
 } //namespace Dali
index 1fcbe88..6f168df 100644 (file)
@@ -43,6 +43,7 @@ public:
    * @param[in] observer FrameReady observer
    * @param[in] cacheSize The size of the cache
    * @param[in] batchSize The size of a batch to load
+   * @param[in] interval Time interval between each frame
    *
    * This will start loading textures immediately, according to the
    * batch and cache sizes.
@@ -51,7 +52,8 @@ public:
                     UrlList&                        urlList,
                     ImageCache::FrameReadyObserver& observer,
                     uint16_t                        cacheSize,
-                    uint16_t                        batchSize);
+                    uint16_t                        batchSize,
+                    uint32_t                        interval);
 
   /**
    * Destructor
@@ -59,73 +61,89 @@ public:
   ~RollingImageCache() override;
 
   /**
-   * Get the Nth frame. If it's not ready, this will trigger the
-   * sending of FrameReady() when the image becomes ready.
+   * @copydoc Internal::ImageCache::Frame()
    */
   TextureSet Frame(uint32_t frameIndex) override;
 
   /**
-   * Get the first frame. If it's not ready, this will trigger the
-   * sending of FrameReady() when the image becomes ready.
+   * @copydoc Internal::ImageCache::FirstFrame()
    */
   TextureSet FirstFrame() override;
 
   /**
-   * Get the next frame. If it's not ready, this will trigger the
-   * sending of FrameReady() when the image becomes ready.
-   */
-  TextureSet NextFrame() override;
-
-  /**
-   * Get the interval of Nth frame.
+   * @copydoc Internal::ImageCache::GetFrameInterval()
    */
   uint32_t GetFrameInterval(uint32_t frameIndex) const override;
 
   /**
-   * Get the current rendered frame index.
-   * If there isn't any loaded frame, returns -1.
+   * @copydoc Internal::ImageCache::GetCurrentFrameIndex()
    */
   int32_t GetCurrentFrameIndex() const override;
 
   /**
-   * Get total frame count of the animated image file.
+   * @copydoc Internal::ImageCache::GetTotalFrameCount()
    */
   int32_t GetTotalFrameCount() const override;
 
+  /**
+   * @copydoc Internal::ImageCache::GetLoadState()
+   */
+  TextureManager::LoadState GetLoadState() const override;
+
+  /**
+   * @copydoc Internal::ImageCache::ClearCache()
+   */
+  void ClearCache() override;
+
 private:
   /**
+   * @brief Check whether the front frame is ready or not.
+   *
    * @return true if the front frame is ready
    */
   bool IsFrontReady() const;
 
   /**
-   * Load the next batch of images
+   * @brief Load the next batch of images
+   *
+   * @param[in] frameIndex starting frame index of batch to be loaded.
    */
-  void LoadBatch();
+  void LoadBatch(uint32_t frameIndex);
 
   /**
-   * Find the matching image frame, and set it to ready
+   * @brief Find the matching image frame, and set it to ready
+   *
+   * @param[in] textureId texture id to be marked as ready.
+   * @param[in] loadSuccess true if the frame loading is succeeded.
    */
-  void SetImageFrameReady(TextureManager::TextureId textureId);
+  void SetImageFrameReady(TextureManager::TextureId textureId, bool loadSuccess);
 
   /**
-   * Get the texture set of the front frame.
-   * @return the texture set
+   * @brief Get the texture set of the front frame.
+   *
+   * @return the texture set of the front of Cache.
    */
   TextureSet GetFrontTextureSet() const;
 
   /**
-   * Get the texture id of the given index
+   * @brief Get the texture id of the given index
+   *
+   * @param[in] index index of the queue.
    */
   TextureManager::TextureId GetCachedTextureId(int index) const;
 
   /**
-   * Check if the front frame has become ready - if so, inform observer
+   * @brief Check if the front frame has become ready - if so, inform observer
+   *
    * @param[in] wasReady Readiness before call.
    */
   void CheckFrontFrame(bool wasReady);
 
 protected:
+
+  /**
+   * @copydoc Toolkit::TextureUploadObserver::UploadComplete()
+   */
   void UploadComplete(
     bool           loadSuccess,
     int32_t        textureId,
@@ -134,12 +152,6 @@ protected:
     const Vector4& atlasRect,
     bool           preMultiplied) override;
 
-  void LoadComplete(
-    bool               loadSuccess,
-    Devel::PixelBuffer pixelBuffer,
-    const VisualUrl&   url,
-    bool               preMultiplied) override;
-
 private:
   /**
    * Secondary class to hold readiness and index into url
@@ -150,8 +162,9 @@ private:
     bool         mReady    = false;
   };
 
-  std::vector<UrlStore>&    mImageUrls;
-  CircularQueue<ImageFrame> mQueue;
+  std::vector<UrlStore>&                 mImageUrls;
+  std::vector<TextureManager::LoadState> mLoadStates;
+  CircularQueue<ImageFrame>              mQueue;
 };
 
 } // namespace Internal
index 093954e..b1f18eb 100644 (file)
@@ -38,9 +38,9 @@
 
 namespace
 {
-constexpr auto INITIAL_CACHE_NUMBER                    = size_t{0u};
-constexpr auto DEFAULT_NUMBER_OF_LOCAL_LOADER_THREADS  = size_t{4u};
-constexpr auto DEFAULT_NUMBER_OF_REMOTE_LOADER_THREADS = size_t{8u};
+constexpr auto INITIAL_CACHE_NUMBER                     = size_t{0u};
+constexpr auto DEFAULT_NUMBER_OF_LOCAL_LOADER_THREADS   = size_t{4u};
+constexpr auto DEFAULT_NUMBER_OF_REMOTE_LOADER_THREADS  = size_t{8u};
 
 constexpr auto NUMBER_OF_LOCAL_LOADER_THREADS_ENV  = "DALI_TEXTURE_LOCAL_THREADS";
 constexpr auto NUMBER_OF_REMOTE_LOADER_THREADS_ENV = "DALI_TEXTURE_REMOTE_THREADS";
@@ -142,11 +142,19 @@ TextureManager::~TextureManager()
   }
 }
 
-TextureSet TextureManager::LoadAnimatedImageTexture(
-  Dali::AnimatedImageLoading animatedImageLoading, uint32_t frameIndex, Dali::SamplingMode::Type samplingMode, bool synchronousLoading, TextureManager::TextureId& textureId, Dali::WrapMode::Type wrapModeU, Dali::WrapMode::Type wrapModeV, TextureUploadObserver* textureObserver)
+TextureSet TextureManager::LoadAnimatedImageTexture(Dali::AnimatedImageLoading animatedImageLoading,
+                                                    uint32_t                   frameIndex,
+                                                    bool&                      loadingStatus,
+                                                    TextureManager::TextureId& textureId,
+                                                    Dali::SamplingMode::Type   samplingMode,
+                                                    Dali::WrapMode::Type       wrapModeU,
+                                                    Dali::WrapMode::Type       wrapModeV,
+                                                    bool                       synchronousLoading,
+                                                    bool                       useCache,
+                                                    TextureUploadObserver*     textureObserver)
 {
+  loadingStatus = false;
   TextureSet textureSet;
-
   if(synchronousLoading)
   {
     Devel::PixelBuffer pixelBuffer;
@@ -172,14 +180,24 @@ TextureSet TextureManager::LoadAnimatedImageTexture(
   }
   else
   {
+    loadingStatus = true;
     auto preMultiply                    = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
-    textureId                           = RequestLoadInternal(animatedImageLoading.GetUrl(), INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, TextureManager::NO_ATLAS, false, StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiply, animatedImageLoading, frameIndex);
+    textureId                           = RequestLoadInternal(animatedImageLoading.GetUrl(), INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, TextureManager::NO_ATLAS, false, StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiply, animatedImageLoading, frameIndex, useCache);
     TextureManager::LoadState loadState = GetTextureStateInternal(textureId);
     if(loadState == TextureManager::LoadState::UPLOADED)
     {
       // UploadComplete has already been called - keep the same texture set
       textureSet = GetTextureSet(textureId);
     }
+
+    // If we are loading the texture, or waiting for the ready signal handler to complete, inform
+    // caller that they need to wait.
+    loadingStatus = (loadState == TextureManager::LoadState::LOADING ||
+                     loadState == TextureManager::LoadState::WAITING_FOR_MASK ||
+                     loadState == TextureManager::LoadState::MASK_APPLYING ||
+                     loadState == TextureManager::LoadState::MASK_APPLIED ||
+                     loadState == TextureManager::LoadState::NOT_STARTED ||
+                     mQueueLoadFlag);
   }
 
   if(textureSet)
@@ -220,7 +238,7 @@ Devel::PixelBuffer TextureManager::LoadPixelBuffer(
   }
   else
   {
-    RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, false, StorageType::RETURN_PIXEL_BUFFER, textureObserver, orientationCorrection, TextureManager::ReloadPolicy::FORCED, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u);
+    RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, false, StorageType::RETURN_PIXEL_BUFFER, textureObserver, orientationCorrection, TextureManager::ReloadPolicy::FORCED, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, false);
   }
 
   return pixelBuffer;
@@ -382,7 +400,7 @@ TextureManager::TextureId TextureManager::RequestLoad(
   TextureManager::ReloadPolicy    reloadPolicy,
   TextureManager::MultiplyOnLoad& preMultiplyOnLoad)
 {
-  return RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, useAtlas, false, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u);
+  return RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, useAtlas, false, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, true);
 }
 
 TextureManager::TextureId TextureManager::RequestLoad(
@@ -399,14 +417,14 @@ TextureManager::TextureId TextureManager::RequestLoad(
   TextureManager::ReloadPolicy    reloadPolicy,
   TextureManager::MultiplyOnLoad& preMultiplyOnLoad)
 {
-  return RequestLoadInternal(url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas, cropToMask, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u);
+  return RequestLoadInternal(url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas, cropToMask, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, true);
 }
 
 TextureManager::TextureId TextureManager::RequestMaskLoad(const VisualUrl& maskUrl)
 {
   // Use the normal load procedure to get the alpha mask.
   auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
-  return RequestLoadInternal(maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, NO_ATLAS, false, StorageType::KEEP_PIXEL_BUFFER, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u);
+  return RequestLoadInternal(maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, NO_ATLAS, false, StorageType::KEEP_PIXEL_BUFFER, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u, true);
 }
 
 TextureManager::TextureId TextureManager::RequestLoadInternal(
@@ -424,19 +442,18 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
   TextureManager::ReloadPolicy    reloadPolicy,
   TextureManager::MultiplyOnLoad& preMultiplyOnLoad,
   Dali::AnimatedImageLoading      animatedImageLoading,
-  uint32_t                        frameIndex)
+  uint32_t                        frameIndex,
+  bool                            useCache)
 {
   // First check if the requested Texture is cached.
-  bool isAnimatedImage = (animatedImageLoading) ? true : false;
-
   TextureHash textureHash = INITIAL_CACHE_NUMBER;
   int         cacheIndex  = INVALID_CACHE_INDEX;
-  if(storageType != StorageType::RETURN_PIXEL_BUFFER && !isAnimatedImage)
+  if(storageType != StorageType::RETURN_PIXEL_BUFFER && useCache)
   {
     textureHash = GenerateHash(url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId);
 
     // Look up the texture by hash. Note: The extra parameters are used in case of a hash collision.
-    cacheIndex = FindCachedTexture(textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, preMultiplyOnLoad);
+    cacheIndex = FindCachedTexture(textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, preMultiplyOnLoad, (animatedImageLoading) ? true : false);
   }
 
   TextureManager::TextureId textureId = INVALID_TEXTURE_ID;
@@ -574,7 +591,6 @@ void TextureManager::Remove(const TextureManager::TextureId textureId, TextureUp
   if(textureInfoIndex != INVALID_INDEX)
   {
     TextureInfo& textureInfo(mTextureInfoContainer[textureInfoIndex]);
-
     DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::Remove(%d) url:%s\n  cacheIdx:%d loadState:%s reference count = %d\n", textureId, textureInfo.url.GetUrl().c_str(), textureInfoIndex, GET_LOAD_STATE_STRING(textureInfo.loadState), textureInfo.referenceCount);
 
     // Decrement the reference count and check if this is the last user of this Texture.
@@ -913,7 +929,14 @@ void TextureManager::LoadOrQueueTexture(TextureInfo& textureInfo, TextureUploadO
       {
         // The Texture has already loaded. The other observers have already been notified.
         // We need to send a "late" loaded notification for this observer.
-        observer->UploadComplete(true, textureInfo.textureId, textureInfo.textureSet, textureInfo.useAtlas, textureInfo.atlasRect, textureInfo.preMultiplied);
+        if(textureInfo.isAnimatedImageFormat)
+        {
+          observer->AnimatedImageUploadComplete(true, textureInfo.textureId, textureInfo.frameCount, textureInfo.frameInterval);
+        }
+        else
+        {
+          observer->UploadComplete(true, textureInfo.textureId, textureInfo.textureSet, textureInfo.useAtlas, textureInfo.atlasRect, textureInfo.preMultiplied);
+        }
       }
       break;
     }
@@ -975,7 +998,14 @@ void TextureManager::ProcessQueuedTextures()
       TextureInfo& textureInfo(mTextureInfoContainer[cacheIndex]);
       if(textureInfo.loadState == LoadState::UPLOADED)
       {
-        element.mObserver->UploadComplete(true, textureInfo.textureId, textureInfo.textureSet, textureInfo.useAtlas, textureInfo.atlasRect, textureInfo.preMultiplied);
+        if(textureInfo.isAnimatedImageFormat)
+        {
+          element.mObserver->AnimatedImageUploadComplete(true, textureInfo.textureId, textureInfo.frameCount, textureInfo.frameInterval);
+        }
+        else
+        {
+          element.mObserver->UploadComplete(true, textureInfo.textureId, textureInfo.textureSet, textureInfo.useAtlas, textureInfo.atlasRect, textureInfo.preMultiplied);
+        }
       }
       else if(textureInfo.loadState == LoadState::LOAD_FINISHED && textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER)
       {
@@ -1192,6 +1222,13 @@ void TextureManager::NotifyObservers(TextureInfo& textureInfo, bool success)
   // and erase it from the list
   TextureInfo* info = &textureInfo;
 
+  if(info->animatedImageLoading)
+  {
+    info->frameCount = info->animatedImageLoading.GetImageCount();
+    info->frameInterval = info->animatedImageLoading.GetFrameInterval(info->frameIndex);
+    info->animatedImageLoading.Reset();
+  }
+
   mQueueLoadFlag = true;
 
   while(info->observerList.Count())
@@ -1218,6 +1255,10 @@ void TextureManager::NotifyObservers(TextureInfo& textureInfo, bool success)
     {
       observer->LoadComplete(success, info->pixelBuffer, info->url, info->preMultiplied);
     }
+    else if(info->isAnimatedImageFormat)
+    {
+      observer->AnimatedImageUploadComplete(success, info->textureId, info->frameCount, info->frameInterval);
+    }
     else
     {
       observer->UploadComplete(success, info->textureId, info->textureSet, info->useAtlas, info->atlasRect, info->preMultiplied);
@@ -1338,7 +1379,8 @@ int TextureManager::FindCachedTexture(
   const Dali::SamplingMode::Type    samplingMode,
   const bool                        useAtlas,
   TextureId                         maskTextureId,
-  TextureManager::MultiplyOnLoad    preMultiplyOnLoad)
+  TextureManager::MultiplyOnLoad    preMultiplyOnLoad,
+  bool                              isAnimatedImage)
 {
   // Default to an invalid ID, in case we do not find a match.
   int cacheIndex = INVALID_CACHE_INDEX;
@@ -1356,6 +1398,7 @@ int TextureManager::FindCachedTexture(
          (useAtlas == textureInfo.useAtlas) &&
          (maskTextureId == textureInfo.maskTextureId) &&
          (size == textureInfo.desiredSize) &&
+         (isAnimatedImage == textureInfo.isAnimatedImageFormat) &&
          ((size.GetWidth() == 0 && size.GetHeight() == 0) ||
           (fittingMode == textureInfo.fittingMode &&
            samplingMode == textureInfo.samplingMode)))
index 48eea78..4fddf49 100644 (file)
@@ -165,26 +165,30 @@ public:
    * The parameters are used to specify how the animated image is loaded.
    * The observer has the LoadComplete method called when the load is ready.
    *
-   * @param[in] animatedImageLoading  The AnimatedImageLoading that contain the animated image information
-   * @param[in] frameIndex            The frame index to load.
-   * @param[in] samplingMode          The SamplingMode to use
-   * @param[in] synchronousLoading    true if the frame should be loaded synchronously
-   * @param[out] textureId            The textureId of the frame
-   * @param[in] wrapModeU             Horizontal Wrap mode
-   * @param[in] wrapModeV             Vertical Wrap mode
-   * @param[in] textureObserver       The client object should inherit from this and provide the "UploadCompleted" virtual.
-   *                                  This is called when an image load completes (or fails).
+   * @param[in]  animatedImageLoading  The AnimatedImageLoading that contain the animated image information
+   * @param[in]  frameIndex            The frame index to load.
+   * @param[out] loadingStatus         The loading status of the texture
+   * @param[out] textureId             The textureId of the frame
+   * @param[in]  samplingMode          The SamplingMode to use
+   * @param[in]  wrapModeU             Horizontal Wrap mode
+   * @param[in]  wrapModeV             Vertical Wrap mode
+   * @param[in]  synchronousLoading    true if the frame should be loaded synchronously
+   * @param[in]  useCache              true if this frame loading uses cache.
+   * @param[in]  textureObserver       The client object should inherit from this and provide the "UploadCompleted" virtual.
+   *                                   This is called when an image load completes (or fails).
    *
-   * @return                          The texture set containing the frame of animated image, or empty if still loading.
+   * @return                           The texture set containing the frame of animated image, or empty if still loading.
    */
 
   TextureSet LoadAnimatedImageTexture(Dali::AnimatedImageLoading animatedImageLoading,
                                       uint32_t                   frameIndex,
-                                      Dali::SamplingMode::Type   samplingMode,
-                                      bool                       synchronousLoading,
+                                      bool&                      loadingStatus,
                                       TextureManager::TextureId& textureId,
+                                      Dali::SamplingMode::Type   samplingMode,
                                       Dali::WrapMode::Type       wrapModeU,
                                       Dali::WrapMode::Type       wrapModeV,
+                                      bool                       synchronousLoading,
+                                      bool                       useCache,
                                       TextureUploadObserver*     textureObserver);
 
   /**
@@ -509,7 +513,8 @@ private:
     TextureManager::ReloadPolicy reloadPolicy,
     MultiplyOnLoad&              preMultiplyOnLoad,
     Dali::AnimatedImageLoading   animatedImageLoading,
-    uint32_t                     frameIndex);
+    uint32_t                     frameIndex,
+    bool useCache);
 
   /**
    * @brief Get the current state of a texture
@@ -558,6 +563,8 @@ private:
       storageType(StorageType::UPLOAD_TO_TEXTURE),
       animatedImageLoading(animatedImageLoading),
       frameIndex(frameIndex),
+      frameCount(0u),
+      frameInterval(0u),
       loadSynchronously(loadSynchronously),
       useAtlas(useAtlas),
       cropToMask(cropToMask),
@@ -565,6 +572,7 @@ private:
       preMultiplyOnLoad(preMultiplyOnLoad),
       preMultiplied(false)
     {
+      isAnimatedImageFormat = (animatedImageLoading) ? true : false;
     }
 
     /**
@@ -590,7 +598,9 @@ private:
     Dali::SamplingMode::Type    samplingMode : 3;      ///< The requested SamplingMode
     StorageType                 storageType;           ///< CPU storage / GPU upload;
     Dali::AnimatedImageLoading  animatedImageLoading;  ///< AnimatedImageLoading that contains animated image information.
-    uint32_t                    frameIndex;            ///< frame index that be loaded, in case of animated image
+    uint32_t                    frameIndex;            ///< Frame index that be loaded, in case of animated image
+    uint32_t                    frameCount;            ///< Total frame count of input animated image. If this variable is not 0, this textureInfo is for animated image file format.
+    uint32_t                    frameInterval;         ///< Time interval between this frame and next frame of animated image.
     bool                        loadSynchronously : 1; ///< True if synchronous loading was requested
     UseAtlas                    useAtlas : 2;          ///< USE_ATLAS if an atlas was requested.
                                                        ///< This is updated to false if atlas is not used
@@ -598,6 +608,7 @@ private:
     bool orientationCorrection : 1;                    ///< true if the image should be rotated to match exif orientation data
     bool preMultiplyOnLoad : 1;                        ///< true if the image's color should be multiplied by it's alpha
     bool preMultiplied : 1;                            ///< true if the image's color was multiplied by it's alpha
+    bool isAnimatedImageFormat : 1;                    ///< true if the image is requested from animated image visual.
   };
 
   /**
@@ -781,7 +792,8 @@ private:
    * @param[in] samplingMode      The SamplingMode to use
    * @param[in] useAtlas          True if atlased
    * @param[in] maskTextureId     Optional texture ID to use to mask this image
-   * @param[in] preMultiplyOnLoad if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha.
+   * @param[in] preMultiplyOnLoad If the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha.
+   * @param[in] isAnimatedImage   True if the texture is from animated image.
    * @return                      A TextureId of a cached Texture if found. Or INVALID_TEXTURE_ID if not found.
    */
   TextureManager::TextureId FindCachedTexture(
@@ -792,7 +804,8 @@ private:
     const Dali::SamplingMode::Type    samplingMode,
     const bool                        useAtlas,
     TextureId                         maskTextureId,
-    MultiplyOnLoad                    preMultiplyOnLoad);
+    MultiplyOnLoad                    preMultiplyOnLoad,
+    bool                              isAnimatedImage);
 
 private:
   /**
index d6657a2..b22b4df 100644 (file)
@@ -21,6 +21,7 @@
 // EXTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
 #include <dali/public-api/signals/dali-signal.h>
+#include <dali/public-api/rendering/texture-set.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/visuals/visual-url.h>
@@ -28,7 +29,6 @@
 
 namespace Dali
 {
-class TextureSet;
 
 namespace Toolkit
 {
@@ -54,7 +54,7 @@ public:
   virtual ~TextureUploadObserver();
 
   /**
-   * The action to be taken once the async load has finished and the upload to GPU is completed.
+   * @brief The action to be taken once the async load has finished and the upload to GPU is completed.
    * This should be overridden by the deriving class.
    *
    * @param[in] loadSuccess True if the texture load was successful (i.e. the resource is available). If false, then the resource failed to load. In future, this will automatically upload a "broken" image.
@@ -64,10 +64,25 @@ public:
    * @param[in] atlasRect   If using atlasing, this is the rectangle within the atlas to use.
    * @param[in] preMultiplied True if the image had pre-multiplied alpha applied
    */
-  virtual void UploadComplete(bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing, const Vector4& atlasRect, bool preMultiplied) = 0;
+  virtual void UploadComplete(bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing, const Vector4& atlasRect, bool preMultiplied)
+  {
+  }
 
   /**
-   * The action to be taken once the async load has finished.
+   * @brief The action to be taken once the async load of animated image has finished and the upload to GPU is completed.
+   * This should be overridden by the deriving class.
+   *
+   * @param[in] loadSuccess   True if the texture load was successful (i.e. the resource is available). If false, then the resource failed to load. In future, this will automatically upload a "broken" image.
+   * @param[in] textureId     The textureId of the loaded texture in the TextureManager
+   * @param[in] frameCount    The frameCount of the animated image
+   * @param[in] interval      Time interval between currently loaded frame and next frame.
+   */
+  virtual void AnimatedImageUploadComplete(bool loadSuccess, int32_t textureId, uint32_t frameCount, uint32_t interval)
+  {
+  }
+
+  /**
+   * @brief The action to be taken once the async load has finished.
    * This should be overridden by the deriving class.
    *
    * @param[in] loadSuccess   True if the image load was successful (i.e. the resource is available). If false, then the resource failed to load.
@@ -75,7 +90,9 @@ public:
    * @param[in] url           The url address of the loaded image.
    * @param[in] preMultiplied True if the image had pre-multiplied alpha applied
    */
-  virtual void LoadComplete(bool loadSuccess, Devel::PixelBuffer pixelBuffer, const Internal::VisualUrl& url, bool preMultiplied) = 0;
+  virtual void LoadComplete(bool loadSuccess, Devel::PixelBuffer pixelBuffer, const Internal::VisualUrl& url, bool preMultiplied)
+  {
+  }
 
   /**
    * @brief Returns the destruction signal.