[dali_2.3.27] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / animated-image / animated-image-visual.cpp
index f4a83dc..d94e0b5 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,8 +19,8 @@
 #include <dali-toolkit/internal/visuals/animated-image/animated-image-visual.h>
 
 // EXTERNAL INCLUDES
 #include <dali-toolkit/internal/visuals/animated-image/animated-image-visual.h>
 
 // EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/window-devel.h>
 #include <dali/devel-api/adaptor-framework/image-loading.h>
 #include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/rendering/decorated-visual-renderer.h>
 #include <memory>
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/rendering/decorated-visual-renderer.h>
 #include <memory>
@@ -190,6 +190,22 @@ void AnimatedImageVisual::InitializeAnimatedImage(const VisualUrl& imageUrl)
 {
   mImageUrl             = imageUrl;
   mAnimatedImageLoading = AnimatedImageLoading::New(imageUrl.GetUrl(), imageUrl.IsLocalResource());
 {
   mImageUrl             = imageUrl;
   mAnimatedImageLoading = AnimatedImageLoading::New(imageUrl.GetUrl(), imageUrl.IsLocalResource());
+
+  // If we fail to load the animated image, we will try to load as a normal image.
+  if(!mAnimatedImageLoading)
+  {
+    mImageUrls = new ImageCache::UrlList();
+    mImageUrls->reserve(SINGLE_IMAGE_COUNT);
+
+    for(unsigned int i = 0; i < SINGLE_IMAGE_COUNT; ++i)
+    {
+      ImageCache::UrlStore urlStore;
+      urlStore.mTextureId = TextureManager::INVALID_TEXTURE_ID;
+      urlStore.mUrl       = imageUrl;
+      mImageUrls->push_back(urlStore);
+    }
+    mFrameCount = SINGLE_IMAGE_COUNT;
+  }
 }
 
 void AnimatedImageVisual::CreateImageCache()
 }
 
 void AnimatedImageVisual::CreateImageCache()
@@ -219,14 +235,14 @@ void AnimatedImageVisual::CreateImageCache()
     }
   }
 
     }
   }
 
-  if(!mImageCache)
+  if(DALI_UNLIKELY(!mImageCache))
   {
     DALI_LOG_ERROR("mImageCache is null\n");
   }
 }
 
 AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, ImageDimensions desiredSize)
   {
     DALI_LOG_ERROR("mImageCache is null\n");
   }
 }
 
 AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, ImageDimensions desiredSize)
-: Visual::Base(factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::ANIMATED_IMAGE),
+: Visual::Base(factoryCache, Visual::FittingMode::DONT_CARE, Toolkit::Visual::ANIMATED_IMAGE),
   mFrameDelayTimer(),
   mPlacementActor(),
   mImageVisualShaderFactory(shaderFactory),
   mFrameDelayTimer(),
   mPlacementActor(),
   mImageVisualShaderFactory(shaderFactory),
@@ -251,7 +267,7 @@ AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, Image
   mActionStatus(DevelAnimatedImageVisual::Action::PLAY),
   mWrapModeU(WrapMode::DEFAULT),
   mWrapModeV(WrapMode::DEFAULT),
   mActionStatus(DevelAnimatedImageVisual::Action::PLAY),
   mWrapModeU(WrapMode::DEFAULT),
   mWrapModeV(WrapMode::DEFAULT),
-  mFittingMode(FittingMode::SCALE_TO_FILL),
+  mFittingMode(FittingMode::VISUAL_FITTING),
   mSamplingMode(SamplingMode::BOX_THEN_LINEAR),
   mStopBehavior(DevelImageVisual::StopBehavior::CURRENT_FRAME),
   mStartFirstFrame(false),
   mSamplingMode(SamplingMode::BOX_THEN_LINEAR),
   mStopBehavior(DevelImageVisual::StopBehavior::CURRENT_FRAME),
   mStartFirstFrame(false),
@@ -266,7 +282,10 @@ AnimatedImageVisual::~AnimatedImageVisual()
   // 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)
   {
   // 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();
+    if(DALI_LIKELY(mImageCache))
+    {
+      mImageCache->ClearCache();
+    }
   }
   delete mImageCache;
   delete mImageUrls;
   }
   delete mImageCache;
   delete mImageUrls;
@@ -276,6 +295,26 @@ void AnimatedImageVisual::GetNaturalSize(Vector2& naturalSize)
 {
   if(mDesiredSize.GetWidth() > 0 && mDesiredSize.GetHeight() > 0)
   {
 {
   if(mDesiredSize.GetWidth() > 0 && mDesiredSize.GetHeight() > 0)
   {
+    if(mImpl->mRenderer)
+    {
+      auto textureSet = mImpl->mRenderer.GetTextures();
+      if(textureSet && textureSet.GetTextureCount())
+      {
+        auto texture = textureSet.GetTexture(0);
+        if(texture)
+        {
+          Dali::Vector2 textureSize;
+          textureSize.x = texture.GetWidth();
+          textureSize.y = texture.GetHeight();
+          if(textureSize != Vector2::ZERO)
+          {
+            naturalSize = textureSize;
+            return;
+          }
+        }
+      }
+    }
+
     naturalSize.x = mDesiredSize.GetWidth();
     naturalSize.y = mDesiredSize.GetHeight();
     return;
     naturalSize.x = mDesiredSize.GetWidth();
     naturalSize.y = mDesiredSize.GetHeight();
     return;
@@ -297,7 +336,7 @@ void AnimatedImageVisual::GetNaturalSize(Vector2& naturalSize)
       }
     }
 
       }
     }
 
-    if(mImageUrl.IsValid())
+    if(mImageUrl.IsValid() && mAnimatedImageLoading)
     {
       mImageSize = mAnimatedImageLoading.GetImageSize();
     }
     {
       mImageSize = mAnimatedImageLoading.GetImageSize();
     }
@@ -344,7 +383,24 @@ void AnimatedImageVisual::DoCreatePropertyMap(Property::Map& map) const
   map.Insert(Toolkit::ImageVisual::Property::FRAME_DELAY, static_cast<int>(mFrameDelay));
   map.Insert(Toolkit::DevelImageVisual::Property::LOOP_COUNT, static_cast<int>(mLoopCount));
   map.Insert(Toolkit::DevelImageVisual::Property::CURRENT_FRAME_NUMBER, (mImageCache) ? static_cast<int32_t>(mImageCache->GetCurrentFrameIndex()) : -1);
   map.Insert(Toolkit::ImageVisual::Property::FRAME_DELAY, static_cast<int>(mFrameDelay));
   map.Insert(Toolkit::DevelImageVisual::Property::LOOP_COUNT, static_cast<int>(mLoopCount));
   map.Insert(Toolkit::DevelImageVisual::Property::CURRENT_FRAME_NUMBER, (mImageCache) ? static_cast<int32_t>(mImageCache->GetCurrentFrameIndex()) : -1);
-  map.Insert(Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, (mImageCache) ? static_cast<int32_t>((mAnimatedImageLoading) ? mAnimatedImageLoading.GetImageCount() : mImageCache->GetTotalFrameCount()) : -1);
+
+  // This returns -1 until the loading is finished.
+  auto frameCount = int32_t(mFrameCount);
+  if(mImageCache && frameCount == 0)
+  {
+    frameCount = mImageCache->GetTotalFrameCount();
+
+    if(frameCount <= int32_t(SINGLE_IMAGE_COUNT) && mAnimatedImageLoading && mAnimatedImageLoading.HasLoadingSucceeded())
+    {
+      frameCount = int32_t(mAnimatedImageLoading.GetImageCount());
+    }
+    else
+    {
+      frameCount = -1;
+    }
+  }
+
+  map.Insert(Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, static_cast<int>(frameCount));
 
   map.Insert(Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, mStopBehavior);
 
 
   map.Insert(Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, mStopBehavior);
 
@@ -368,11 +424,8 @@ void AnimatedImageVisual::DoCreateInstancePropertyMap(Property::Map& map) const
 {
   map.Clear();
   map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::ANIMATED_IMAGE);
 {
   map.Clear();
   map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::ANIMATED_IMAGE);
-  if(mImageUrl.IsValid())
-  {
-    map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
-    map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
-  }
+  map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
+  map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
 }
 
 void AnimatedImageVisual::OnDoAction(const Dali::Property::Index actionId, const Dali::Property::Value& attributes)
 }
 
 void AnimatedImageVisual::OnDoAction(const Dali::Property::Index actionId, const Dali::Property::Value& attributes)
@@ -611,7 +664,7 @@ void AnimatedImageVisual::DoSetProperty(Property::Index        index,
       if(value.Get(frameDelay))
       {
         mFrameDelay = frameDelay;
       if(value.Get(frameDelay))
       {
         mFrameDelay = frameDelay;
-        if(mImageCache)
+        if(DALI_LIKELY(mImageCache))
         {
           mImageCache->SetInterval(static_cast<uint32_t>(mFrameDelay));
         }
         {
           mImageCache->SetInterval(static_cast<uint32_t>(mFrameDelay));
         }
@@ -766,7 +819,7 @@ void AnimatedImageVisual::DoSetOnScene(Actor& actor)
   mPlacementActor  = actor;
   PrepareTextureSet();
 
   mPlacementActor  = actor;
   PrepareTextureSet();
 
-  DevelActor::VisibilityChangedSignal(actor).Connect(this, &AnimatedImageVisual::OnControlVisibilityChanged);
+  actor.InheritedVisibilityChangedSignal().Connect(this, &AnimatedImageVisual::OnControlInheritedVisibilityChanged);
 
   Window window = DevelWindow::Get(actor);
   if(window)
 
   Window window = DevelWindow::Get(actor);
   if(window)
@@ -789,7 +842,10 @@ void AnimatedImageVisual::DoSetOffScene(Actor& actor)
   actor.RemoveRenderer(mImpl->mRenderer);
   if(mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED)
   {
   actor.RemoveRenderer(mImpl->mRenderer);
   if(mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED)
   {
-    mImageCache->ClearCache(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas
+    if(DALI_LIKELY(mImageCache))
+    {
+      mImageCache->ClearCache(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas
+    }
     mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING;
 
     TextureSet textureSet = TextureSet::New();
     mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING;
 
     TextureSet textureSet = TextureSet::New();
@@ -801,7 +857,7 @@ void AnimatedImageVisual::DoSetOffScene(Actor& actor)
   mCurrentFrameIndex = FIRST_FRAME_INDEX;
   mCurrentLoopIndex  = FIRST_LOOP;
 
   mCurrentFrameIndex = FIRST_FRAME_INDEX;
   mCurrentLoopIndex  = FIRST_LOOP;
 
-  DevelActor::VisibilityChangedSignal(actor).Disconnect(this, &AnimatedImageVisual::OnControlVisibilityChanged);
+  actor.InheritedVisibilityChangedSignal().Disconnect(this, &AnimatedImageVisual::OnControlInheritedVisibilityChanged);
 
   Window window = mPlacementWindow.GetHandle();
   if(window)
 
   Window window = mPlacementWindow.GetHandle();
   if(window)
@@ -919,10 +975,15 @@ void AnimatedImageVisual::StartFirstFrame(TextureSet& textureSet, uint32_t first
 void AnimatedImageVisual::PrepareTextureSet()
 {
   TextureSet textureSet;
 void AnimatedImageVisual::PrepareTextureSet()
 {
   TextureSet textureSet;
-  if(mImageCache)
+  if(DALI_LIKELY(mImageCache))
   {
     textureSet = mImageCache->FirstFrame();
   }
   {
     textureSet = mImageCache->FirstFrame();
   }
+  else
+  {
+    // preMultiplied should be false because broken image don't premultiply alpha on load
+    FrameReady(TextureSet(), 0, false);
+  }
 
   // Check whether synchronous loading is true or false for the first frame.
   if(textureSet)
 
   // Check whether synchronous loading is true or false for the first frame.
   if(textureSet)
@@ -973,7 +1034,10 @@ void AnimatedImageVisual::FrameReady(TextureSet textureSet, uint32_t interval, b
 
   if(mStartFirstFrame)
   {
 
   if(mStartFirstFrame)
   {
-    mFrameCount = mImageCache->GetTotalFrameCount();
+    if(DALI_LIKELY(mImageCache))
+    {
+      mFrameCount = mImageCache->GetTotalFrameCount();
+    }
     StartFirstFrame(textureSet, interval);
   }
   else
     StartFirstFrame(textureSet, interval);
   }
   else
@@ -995,7 +1059,7 @@ bool AnimatedImageVisual::DisplayNextFrame()
   TextureSet textureSet;
   bool       continueTimer = false;
 
   TextureSet textureSet;
   bool       continueTimer = false;
 
-  if(mImageCache)
+  if(DALI_LIKELY(mImageCache))
   {
     uint32_t frameIndex = mImageCache->GetCurrentFrameIndex();
 
   {
     uint32_t frameIndex = mImageCache->GetCurrentFrameIndex();
 
@@ -1077,8 +1141,13 @@ TextureSet AnimatedImageVisual::SetLoadingFailed()
   {
     imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
   }
   {
     imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
   }
-  mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
-  TextureSet textureSet = mImpl->mRenderer.GetTextures();
+
+  TextureSet textureSet;
+  if(DALI_LIKELY(mImpl->mRenderer))
+  {
+    mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
+    textureSet = mImpl->mRenderer.GetTextures();
+  }
 
   if(mFrameDelayTimer)
   {
 
   if(mFrameDelayTimer)
   {
@@ -1117,13 +1186,13 @@ void AnimatedImageVisual::CheckMaskTexture()
   }
 }
 
   }
 }
 
-void AnimatedImageVisual::OnControlVisibilityChanged(Actor actor, bool visible, DevelActor::VisibilityChange::Type type)
+void AnimatedImageVisual::OnControlInheritedVisibilityChanged(Actor actor, bool visible)
 {
   if(!visible && mActionStatus != DevelAnimatedImageVisual::Action::STOP)
   {
     mActionStatus = DevelAnimatedImageVisual::Action::STOP;
     DisplayNextFrame();
 {
   if(!visible && mActionStatus != DevelAnimatedImageVisual::Action::STOP)
   {
     mActionStatus = DevelAnimatedImageVisual::Action::STOP;
     DisplayNextFrame();
-    DALI_LOG_INFO(gAnimImgLogFilter, Debug::Verbose, "AnimatedImageVisual::OnControlVisibilityChanged: invisibile. Pause animation [%p]\n", this);
+    DALI_LOG_INFO(gAnimImgLogFilter, Debug::Verbose, "AnimatedImageVisual::OnControlInheritedVisibilityChanged: invisibile. Pause animation [%p]\n", this);
   }
 }
 
   }
 }