Add Jump_to frame and StopBehavior of Animated-image-visual(agif) 22/227522/16
authorSeungho, Baek <sbsh.baek@samsung.com>
Thu, 12 Mar 2020 07:39:50 +0000 (16:39 +0900)
committerSeungho, Baek <sbsh.baek@samsung.com>
Tue, 31 Mar 2020 06:47:07 +0000 (15:47 +0900)
 - Added Jump_to action. To directly go to a frame.
 - Added StopBehavior to stop agif at the first, current, and last frame

Change-Id: I76fe813fd694df89e8cc8748cc2a82b69ed7a613
Signed-off-by: Seungho, Baek <sbsh.baek@samsung.com>
12 files changed:
automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp
dali-toolkit/devel-api/visuals/animated-image-visual-actions-devel.h
dali-toolkit/devel-api/visuals/image-visual-properties-devel.h
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.h
dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.h
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h

index 082bbe0..bb591dd 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
 
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -159,6 +159,191 @@ int UtcDaliAnimatedImageVisualGetPropertyMap02(void)
 }
 
 
 }
 
 
+int UtcDaliAnimatedImageVisualJumpToAction(void)
+{
+  ToolkitTestApplication application;
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  Property::Array urls;
+  CopyUrlsIntoArray( urls );
+
+  {
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE );
+    propertyMap.Insert( ImageVisual::Property::URL, Property::Value(urls) );
+    propertyMap.Insert( ImageVisual::Property::BATCH_SIZE, 4);
+    propertyMap.Insert( ImageVisual::Property::CACHE_SIZE, 12);
+    propertyMap.Insert( ImageVisual::Property::FRAME_DELAY, 20);
+
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+
+    DummyControl dummyControl = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+    Stage::GetCurrent().Add( dummyControl );
+    application.SendNotification();
+    application.Render(20);
+
+    tet_infoline( "Ready the visual after the visual is on stage" );
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 4 ), true, TEST_LOCATION );
+
+    tet_infoline( "Test that a timer has been started" );
+    DALI_TEST_EQUALS( Test::GetTimerCount(), 1, TEST_LOCATION );
+
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    application.SendNotification();
+    application.Render(20);
+
+    DALI_TEST_EQUALS( gl.GetLastGenTextureId(), 4, TEST_LOCATION );
+
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::STOP, Property::Map() );
+
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 4, TEST_LOCATION );
+
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::JUMP_TO, 20 );
+
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 4, TEST_LOCATION );
+
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::JUMP_TO, 6 );
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 6 ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 4, TEST_LOCATION );
+
+    dummyControl.Unparent();
+  }
+  tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliAnimatedImageVisualStopBehavior(void)
+{
+  ToolkitTestApplication application;
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  Property::Array urls;
+  CopyUrlsIntoArray( urls );
+
+  {
+    Property::Map propertyMap;
+    propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE );
+    propertyMap.Insert( ImageVisual::Property::URL, Property::Value(urls) );
+    propertyMap.Insert( DevelImageVisual::Property::STOP_BEHAVIOR, DevelImageVisual::StopBehavior::FIRST_FRAME);
+    propertyMap.Insert( ImageVisual::Property::BATCH_SIZE, 4);
+    propertyMap.Insert( ImageVisual::Property::CACHE_SIZE, 8);
+    propertyMap.Insert( ImageVisual::Property::FRAME_DELAY, 20);
+
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+
+    // Expect that a batch of 4 textures has been requested. These will be serially loaded
+    // below.
+
+    DummyControl dummyControl = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+    Stage::GetCurrent().Add( dummyControl );
+    application.SendNotification();
+    application.Render(20);
+
+    tet_infoline( "Ready the visual after the visual is on stage" );
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 4 ), true, TEST_LOCATION );
+
+    tet_infoline( "Test that a timer has been started" );
+    DALI_TEST_EQUALS( Test::GetTimerCount(), 1, TEST_LOCATION );
+
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    application.SendNotification();
+    application.Render(20);
+
+    DALI_TEST_EQUALS( gl.GetLastGenTextureId(), 4, TEST_LOCATION );
+
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::STOP, Property::Map() );
+
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 4, TEST_LOCATION );
+
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::JUMP_TO, 1 );
+
+    // Expect the second batch has been requested
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 4 ), true, TEST_LOCATION );
+
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 4, TEST_LOCATION );
+
+    dummyControl.Unparent();
+  }
+  tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliAnimatedImageVisualGif01(void)
+{
+  ToolkitTestApplication application;
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  {
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE, Visual::ANIMATED_IMAGE );
+    propertyMap.Insert( ImageVisual::Property::URL, TEST_GIF_FILE_NAME );
+    propertyMap.Insert( ImageVisual::Property::BATCH_SIZE, 2);
+    propertyMap.Insert( ImageVisual::Property::CACHE_SIZE, 4);
+    propertyMap.Insert( ImageVisual::Property::FRAME_DELAY, 20);
+
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+
+    // Expect that a batch of 4 textures has been requested. These will be serially loaded
+    // below.
+
+    DummyControl dummyControl = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+    Stage::GetCurrent().Add( dummyControl );
+    application.SendNotification();
+    application.Render(20);
+
+    DALI_TEST_EQUALS( gl.GetLastGenTextureId(), 2, TEST_LOCATION );
+
+    tet_infoline( "Test that a timer has been started" );
+
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    Test::EmitGlobalTimerSignal();
+
+    application.SendNotification();
+    application.Render(20);
+
+    DALI_TEST_EQUALS( gl.GetLastGenTextureId(), 4, TEST_LOCATION );
+
+    dummyControl.Unparent();
+  }
+  tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.SendNotification();
+  application.Render(20);
+  DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 0, TEST_LOCATION );
+
+  END_TEST;
+}
 
 
 int UtcDaliAnimatedImageVisualMultiImage01(void)
 
 
 int UtcDaliAnimatedImageVisualMultiImage01(void)
@@ -574,6 +759,10 @@ void TestLoopCount( ToolkitTestApplication &application, DummyControl &dummyCont
   {
     for ( uint16_t j = 0; j < frameCount; j++ )
     {
   {
     for ( uint16_t j = 0; j < frameCount; j++ )
     {
+      if( i == 0 && j == 0 )
+      {
+        continue; // Because first frame is already showed and we call 2nd frame at the first time of timer animation.
+      }
       tet_printf( "Test that after %u ticks, and we have %u frame \n", j + 1u, j + 1u );
       Test::EmitGlobalTimerSignal();
       application.SendNotification();
       tet_printf( "Test that after %u ticks, and we have %u frame \n", j + 1u, j + 1u );
       Test::EmitGlobalTimerSignal();
       application.SendNotification();
index b654a69..4218045 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_DEVEL_API_VISUALS_ANIMATED_IMAGE_VISUAL_ACTIONS_DEVEL_H
 
 /*
 #define DALI_TOOLKIT_DEVEL_API_VISUALS_ANIMATED_IMAGE_VISUAL_ACTIONS_DEVEL_H
 
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -39,7 +39,8 @@ enum Type
 {
   PLAY,        ///< Play the animated GIF. This is also Default playback mode.
   PAUSE,       ///< Pause the animated GIF.
 {
   PLAY,        ///< Play the animated GIF. This is also Default playback mode.
   PAUSE,       ///< Pause the animated GIF.
-  STOP         ///< Stop the animated GIF.
+  STOP,        ///< Stop the animated GIF.
+  JUMP_TO      ///< Jump to the specified frame. Property::INTEGER value should be passed.
 };
 
 } // namespace Action
 };
 
 } // namespace Action
index 5419799..e6e5303 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_DEVEL_API_VISUALS_IMAGE_VISUAL_PROPERTIES_DEVEL_H
 
 /*
 #define DALI_TOOLKIT_DEVEL_API_VISUALS_IMAGE_VISUAL_PROPERTIES_DEVEL_H
 
 /*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -122,7 +122,7 @@ enum Type
   TOTAL_FRAME_NUMBER = ORIENTATION_CORRECTION + 7,
 
   /**
   TOTAL_FRAME_NUMBER = ORIENTATION_CORRECTION + 7,
 
   /**
-   * @brief  The stop behavior the AnimatedVectorImageVisual will use.
+   * @brief  The stop behavior the AnimatedImageVisual and AnimatedVectorImageVisual will use.
    * @details Name "stopBehavior", Type StopBehavior::Type (Property::INTEGER)
    * @note Default value is StopBehavior::CURRENT_FRAME.
    */
    * @details Name "stopBehavior", Type StopBehavior::Type (Property::INTEGER)
    * @note Default value is StopBehavior::CURRENT_FRAME.
    */
index b1463ba..a0ebe45 100755 (executable)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -49,6 +49,13 @@ namespace Internal
 
 namespace
 {
 
 namespace
 {
+// stop behavior
+DALI_ENUM_TO_STRING_TABLE_BEGIN( STOP_BEHAVIOR )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::DevelImageVisual::StopBehavior, CURRENT_FRAME )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::DevelImageVisual::StopBehavior, FIRST_FRAME )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::DevelImageVisual::StopBehavior, LAST_FRAME )
+DALI_ENUM_TO_STRING_TABLE_END( STOP_BEHAVIOR )
+
 // wrap modes
 DALI_ENUM_TO_STRING_TABLE_BEGIN( WRAP_MODE )
 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, DEFAULT )
 // wrap modes
 DALI_ENUM_TO_STRING_TABLE_BEGIN( WRAP_MODE )
 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, DEFAULT )
@@ -182,7 +189,9 @@ AnimatedImageVisual::AnimatedImageVisual( VisualFactoryCache& factoryCache, Imag
   mWrapModeU( WrapMode::DEFAULT ),
   mWrapModeV( WrapMode::DEFAULT ),
   mActionStatus( DevelAnimatedImageVisual::Action::PLAY ),
   mWrapModeU( WrapMode::DEFAULT ),
   mWrapModeV( WrapMode::DEFAULT ),
   mActionStatus( DevelAnimatedImageVisual::Action::PLAY ),
-  mStartFirstFrame(false)
+  mStopBehavior( DevelImageVisual::StopBehavior::CURRENT_FRAME ),
+  mStartFirstFrame(false),
+  mIsJumpTo( false )
 {}
 
 AnimatedImageVisual::~AnimatedImageVisual()
 {}
 
 AnimatedImageVisual::~AnimatedImageVisual()
@@ -238,6 +247,8 @@ void AnimatedImageVisual::DoCreatePropertyMap( Property::Map& map ) const
   map.Insert( Toolkit::ImageVisual::Property::CACHE_SIZE, static_cast<int>(mCacheSize) );
   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::ImageVisual::Property::CACHE_SIZE, static_cast<int>(mCacheSize) );
   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::STOP_BEHAVIOR, mStopBehavior );
 }
 
 void AnimatedImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
 }
 
 void AnimatedImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
@@ -270,8 +281,32 @@ void AnimatedImageVisual::OnDoAction( const Dali::Property::Index actionId, cons
     {
       // STOP reset functionality will actually be done in a future change
       // Stop will be executed on next timer tick
     {
       // STOP reset functionality will actually be done in a future change
       // Stop will be executed on next timer tick
-      mCurrentFrameIndex = 0;
       mActionStatus = DevelAnimatedImageVisual::Action::STOP;
       mActionStatus = DevelAnimatedImageVisual::Action::STOP;
+      if( IsOnStage() )
+      {
+        DisplayNextFrame();
+      }
+      break;
+    }
+    case DevelAnimatedImageVisual::Action::JUMP_TO:
+    {
+      int32_t frameNumber;
+      if( attributes.Get( frameNumber ) )
+      {
+        if( frameNumber < 0 || frameNumber >= static_cast<int32_t>( mFrameCount ) )
+        {
+          DALI_LOG_ERROR( "Invalid frame index used.\n" );
+        }
+        else
+        {
+          mIsJumpTo = true;
+          mCurrentFrameIndex = frameNumber;
+          if( IsOnStage() )
+          {
+            DisplayNextFrame();
+          }
+        }
+      }
       break;
     }
   }
       break;
     }
   }
@@ -318,6 +353,10 @@ void AnimatedImageVisual::DoSetProperties( const Property::Map& propertyMap )
       {
         DoSetProperty( Toolkit::DevelImageVisual::Property::LOOP_COUNT, keyValue.second );
       }
       {
         DoSetProperty( Toolkit::DevelImageVisual::Property::LOOP_COUNT, keyValue.second );
       }
+      else if( keyValue.first == STOP_BEHAVIOR_NAME )
+      {
+         DoSetProperty( Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, keyValue.second );
+      }
     }
   }
 }
     }
   }
 }
@@ -398,6 +437,16 @@ void AnimatedImageVisual::DoSetProperty( Property::Index index,
       }
       break;
     }
       }
       break;
     }
+
+    case Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR:
+    {
+      int32_t stopBehavior = mStopBehavior;
+      if( Scripting::GetEnumerationProperty( value, STOP_BEHAVIOR_TABLE, STOP_BEHAVIOR_TABLE_COUNT, stopBehavior ) )
+      {
+        mStopBehavior = DevelImageVisual::StopBehavior::Type( stopBehavior );
+      }
+      break;
+    }
   }
 }
 
   }
 }
 
@@ -518,7 +567,7 @@ void AnimatedImageVisual::LoadFirstBatch()
 
   if (!mImageCache)
   {
 
   if (!mImageCache)
   {
-    DALI_LOG_ERROR("mImageCache is null");
+    DALI_LOG_ERROR("mImageCache is null\n");
   }
 }
 
   }
 }
 
@@ -606,45 +655,75 @@ void AnimatedImageVisual::FrameReady( TextureSet textureSet )
 
 bool AnimatedImageVisual::DisplayNextFrame()
 {
 
 bool AnimatedImageVisual::DisplayNextFrame()
 {
-  if( mActionStatus == DevelAnimatedImageVisual::Action::STOP || mActionStatus == DevelAnimatedImageVisual::Action::PAUSE )
+  if( mIsJumpTo )
+  {
+    mIsJumpTo = false;
+  }
+  else if( mActionStatus == DevelAnimatedImageVisual::Action::PAUSE )
   {
     return false;
   }
   {
     return false;
   }
-  if( mFrameCount > 1 )
+  else if( mActionStatus == DevelAnimatedImageVisual::Action::STOP )
   {
   {
-    // Wrap the frame index
-    ++mCurrentFrameIndex;
-
-    if( mLoopCount < 0 || mCurrentLoopIndex < mLoopCount)
+    mCurrentLoopIndex = 0;
+    if( mStopBehavior == DevelImageVisual::StopBehavior::FIRST_FRAME )
     {
     {
-      mCurrentFrameIndex %= mFrameCount;
-      if( mCurrentFrameIndex == 0 )
-      {
-        ++mCurrentLoopIndex;
-      }
+      mCurrentFrameIndex = 0;
+    }
+    else if( mStopBehavior == DevelImageVisual::StopBehavior::LAST_FRAME )
+    {
+      mCurrentFrameIndex = mFrameCount - 1;
     }
     else
     {
     }
     else
     {
-      // This will stop timer
-      return false;
+      return false; // Do not draw already rendered scene twice.
     }
   }
     }
   }
-  DALI_LOG_INFO( gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::DisplayNextFrame(this:%p) FrameCount:%d\n", this, mCurrentFrameIndex);
-
-  if( mFrameDelayContainer.Count() > 0 )
+  else
   {
   {
-    unsigned int delay = mFrameDelayContainer[mCurrentFrameIndex];
+    if( mFrameCount > 1 )
+    {
+      // Wrap the frame index
+      bool finished = false;
+      ++mCurrentFrameIndex;
+      if( mCurrentFrameIndex >= mFrameCount )
+      {
+        ++mCurrentLoopIndex;
+        finished = true;
+      }
 
 
-    if( mFrameDelayTimer.GetInterval() != delay )
+      if( mLoopCount < 0 || mCurrentLoopIndex < mLoopCount)
+      {
+        if( finished )
+        {
+          mCurrentFrameIndex = 0; // Back to the first frame
+        }
+      }
+      else
+      {
+        // This will stop timer
+        mActionStatus = DevelAnimatedImageVisual::Action::STOP;
+        return DisplayNextFrame();
+      }
+    }
+
+    if( mFrameDelayContainer.Count() > 0 )
     {
     {
-      mFrameDelayTimer.SetInterval( delay );
+      unsigned int delay = mFrameDelayContainer[mCurrentFrameIndex];
+
+      if( mFrameDelayTimer.GetInterval() != delay )
+      {
+        mFrameDelayTimer.SetInterval( delay );
+      }
     }
   }
 
     }
   }
 
+  DALI_LOG_INFO( gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::DisplayNextFrame(this:%p) CurrentFrameIndex:%d\n", this, mCurrentFrameIndex);
+
   TextureSet textureSet;
   if( mImageCache )
   {
   TextureSet textureSet;
   if( mImageCache )
   {
-    textureSet = mImageCache->NextFrame();
+    textureSet = mImageCache->Frame( mCurrentFrameIndex );
     if( textureSet )
     {
       SetImageSize( textureSet );
     if( textureSet )
     {
       SetImageSize( textureSet );
@@ -652,8 +731,7 @@ bool AnimatedImageVisual::DisplayNextFrame()
     }
   }
 
     }
   }
 
-  // Keep timer ticking
-  return true;
+  return ( mActionStatus == DevelAnimatedImageVisual::Action::PLAY ) ? true : false;
 }
 
 
 }
 
 
index 791783d..0d21f97 100755 (executable)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_ANIMATED_IMAGE_VISUAL_H
 
 /*
 #define DALI_TOOLKIT_INTERNAL_ANIMATED_IMAGE_VISUAL_H
 
 /*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -265,7 +265,9 @@ private:
   Dali::WrapMode::Type mWrapModeU:3;
   Dali::WrapMode::Type mWrapModeV:3;
   DevelAnimatedImageVisual::Action::Type mActionStatus:3;
   Dali::WrapMode::Type mWrapModeU:3;
   Dali::WrapMode::Type mWrapModeV:3;
   DevelAnimatedImageVisual::Action::Type mActionStatus:3;
+  DevelImageVisual::StopBehavior::Type   mStopBehavior:2;
   bool mStartFirstFrame:1;
   bool mStartFirstFrame:1;
+  bool mIsJumpTo:1;
 };
 
 } // namespace Internal
 };
 
 } // namespace Internal
index 9acf1af..d71ee94 100644 (file)
@@ -54,6 +54,27 @@ FixedImageCache::~FixedImageCache()
   }
 }
 
   }
 }
 
+TextureSet FixedImageCache::Frame( uint32_t frameIndex )
+{
+  while( frameIndex > mFront )
+  {
+    NextFrame();
+  }
+  mFront = frameIndex;
+
+  TextureSet textureSet;
+  if( IsFrontReady() == true )
+  {
+    textureSet = GetFrontTextureSet();
+  }
+  else
+  {
+    mWaitingForReadyFrame = true;
+  }
+
+  return textureSet;
+}
+
 TextureSet FixedImageCache::FirstFrame()
 {
   TextureSet textureSet = GetFrontTextureSet();
 TextureSet FixedImageCache::FirstFrame()
 {
   TextureSet textureSet = GetFrontTextureSet();
@@ -80,7 +101,6 @@ TextureSet FixedImageCache::NextFrame()
   {
     mWaitingForReadyFrame = true;
   }
   {
     mWaitingForReadyFrame = true;
   }
-
   LoadBatch();
 
   return textureSet;
   LoadBatch();
 
   return textureSet;
@@ -96,7 +116,7 @@ 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.
   // 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();;
+  bool frontFrameReady = IsFrontReady();
 
   for( unsigned int i=0; i< mBatchSize && mUrlIndex < mImageUrls.size(); ++i )
   {
 
   for( unsigned int i=0; i< mBatchSize && mUrlIndex < mImageUrls.size(); ++i )
   {
index 72484a4..d884e28 100644 (file)
@@ -49,6 +49,12 @@ public:
   virtual ~FixedImageCache();
 
   /**
   virtual ~FixedImageCache();
 
   /**
+   * Get the Nth frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   */
+  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.
    */
    * Get the first frame. If it's not ready, this will trigger the
    * sending of FrameReady() when the image becomes ready.
    */
index ef1efed..7354992 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_IMAGE_CACHE_H
 
 /*
 #define DALI_TOOLKIT_INTERNAL_IMAGE_CACHE_H
 
 /*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -46,7 +46,7 @@ public:
 
   struct UrlStore
   {
 
   struct UrlStore
   {
-    TextureManager::TextureId mTextureId;
+    TextureManager::TextureId mTextureId = TextureManager::INVALID_TEXTURE_ID;
     std::string mUrl;
   };
 
     std::string mUrl;
   };
 
@@ -85,6 +85,12 @@ public:
    */
   virtual TextureSet NextFrame() = 0;
 
    */
   virtual TextureSet NextFrame() = 0;
 
+  /**
+   * Get the Nth frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   */
+  virtual TextureSet Frame( uint32_t frameIndex ) = 0;
+
 private:
 
   /**
 private:
 
   /**
index 4854076..04f0f1d 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -84,16 +84,49 @@ RollingGifImageCache::~RollingGifImageCache()
   }
 }
 
   }
 }
 
+TextureSet RollingGifImageCache::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 )
+  {
+    mFrameIndex = frameIndex;
+    while( !mQueue.IsEmpty() )
+    {
+      ImageFrame imageFrame = mQueue.PopFront();
+      Dali::Toolkit::TextureManager::RemoveTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl );
+      mImageUrls[ imageFrame.mFrameNumber ].mTextureId = TextureManager::INVALID_TEXTURE_ID;
+    }
+    LoadBatch();
+  }
+  // If the frame is already loaded, remove previous frames of the frame in the queue
+  // and load new frames amount of removed frames.
+  else
+  {
+    bool popExist = false;
+    while( !mQueue.IsEmpty() && mQueue.Front().mFrameNumber != frameIndex )
+    {
+      ImageFrame imageFrame = mQueue.PopFront();
+      Dali::Toolkit::TextureManager::RemoveTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl );
+      mImageUrls[ imageFrame.mFrameNumber ].mTextureId = TextureManager::INVALID_TEXTURE_ID;
+      popExist = true;
+    }
+    if( popExist )
+    {
+      mFrameIndex = ( mQueue.Back().mFrameNumber + 1 ) % mFrameCount;
+      LoadBatch();
+    }
+  }
+
+  return GetFrontTextureSet();
+}
 
 TextureSet RollingGifImageCache::FirstFrame()
 {
 
 TextureSet RollingGifImageCache::FirstFrame()
 {
-  return GetFrontTextureSet();
+  return Frame( 0u );
 }
 
 TextureSet RollingGifImageCache::NextFrame()
 {
 }
 
 TextureSet RollingGifImageCache::NextFrame()
 {
-  TextureSet textureSet;
-
   ImageFrame imageFrame = mQueue.PopFront();
   Dali::Toolkit::TextureManager::RemoveTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl );
   mImageUrls[ imageFrame.mFrameNumber ].mTextureId = TextureManager::INVALID_TEXTURE_ID;
   ImageFrame imageFrame = mQueue.PopFront();
   Dali::Toolkit::TextureManager::RemoveTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl );
   mImageUrls[ imageFrame.mFrameNumber ].mTextureId = TextureManager::INVALID_TEXTURE_ID;
@@ -120,7 +153,7 @@ void RollingGifImageCache::LoadBatch()
   int batchSize = std::min( std::size_t(mBatchSize), mCacheSize - mQueue.Count() );
   DALI_LOG_INFO( gAnimImgLogFilter, Debug::Concise, "RollingGifImageCache::LoadBatch() mFrameIndex:%d  batchSize:%d\n", mFrameIndex, batchSize );
 
   int batchSize = std::min( std::size_t(mBatchSize), mCacheSize - mQueue.Count() );
   DALI_LOG_INFO( gAnimImgLogFilter, Debug::Concise, "RollingGifImageCache::LoadBatch() mFrameIndex:%d  batchSize:%d\n", mFrameIndex, batchSize );
 
-  if( mGifLoading.LoadNextNFrames(  mFrameIndex, batchSize, pixelDataList) )
+  if( mGifLoading.LoadNextNFrames( mFrameIndex, batchSize, pixelDataList) )
   {
     unsigned int pixelDataListCount = pixelDataList.size();
 
   {
     unsigned int pixelDataListCount = pixelDataList.size();
 
index 981274c..91a1210 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_ROLLING_GIF_IMAGE_CACHE_H
 
 /*
 #define DALI_TOOLKIT_INTERNAL_ROLLING_GIF_IMAGE_CACHE_H
 
 /*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -65,6 +65,12 @@ public:
   virtual ~RollingGifImageCache();
 
   /**
   virtual ~RollingGifImageCache();
 
   /**
+   * Get the Nth frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   */
+  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.
    */
    * Get the first frame. If it's not ready, this will trigger the
    * sending of FrameReady() when the image becomes ready.
    */
index b7b45ff..21f81b7 100644 (file)
@@ -80,11 +80,45 @@ RollingImageCache::~RollingImageCache()
   }
 }
 
   }
 }
 
-TextureSet RollingImageCache::FirstFrame()
+TextureSet RollingImageCache::Frame( uint32_t frameIndex )
 {
 {
-  TextureSet textureSet = GetFrontTextureSet();
+  // If a frame of frameIndex is not loaded, clear the queue and remove all loaded textures.
+  if( mImageUrls[ frameIndex ].mTextureId == TextureManager::INVALID_TEXTURE_ID )
+  {
+    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();
+  }
+  // If the frame is already loaded, remove previous frames of the frame in the queue
+  // and load new frames amount of removed frames.
+  else
+  {
+    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 )
+    {
+      mUrlIndex = ( mQueue.Back().mUrlIndex + 1 ) % mImageUrls.size();
+      LoadBatch();
+    }
+  }
 
 
-  if( ! textureSet )
+  TextureSet textureSet;
+  if( IsFrontReady() == true )
+  {
+    textureSet = GetFrontTextureSet();
+  }
+  else
   {
     mWaitingForReadyFrame = true;
   }
   {
     mWaitingForReadyFrame = true;
   }
@@ -92,6 +126,11 @@ TextureSet RollingImageCache::FirstFrame()
   return textureSet;
 }
 
   return textureSet;
 }
 
+TextureSet RollingImageCache::FirstFrame()
+{
+  return Frame( 0u );
+}
+
 TextureSet RollingImageCache::NextFrame()
 {
   TextureSet textureSet;
 TextureSet RollingImageCache::NextFrame()
 {
   TextureSet textureSet;
@@ -100,6 +139,8 @@ TextureSet RollingImageCache::NextFrame()
   mTextureManager.Remove( mImageUrls[ imageFrame.mUrlIndex ].mTextureId, this );
   mImageUrls[ imageFrame.mUrlIndex ].mTextureId = TextureManager::INVALID_TEXTURE_ID;
 
   mTextureManager.Remove( mImageUrls[ imageFrame.mUrlIndex ].mTextureId, this );
   mImageUrls[ imageFrame.mUrlIndex ].mTextureId = TextureManager::INVALID_TEXTURE_ID;
 
+  LoadBatch();
+
   if( IsFrontReady() == true )
   {
     textureSet = GetFrontTextureSet();
   if( IsFrontReady() == true )
   {
     textureSet = GetFrontTextureSet();
@@ -109,8 +150,6 @@ TextureSet RollingImageCache::NextFrame()
     mWaitingForReadyFrame = true;
   }
 
     mWaitingForReadyFrame = true;
   }
 
-  LoadBatch();
-
   return textureSet;
 }
 
   return textureSet;
 }
 
@@ -124,7 +163,7 @@ void RollingImageCache::LoadBatch()
   // 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
   // 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();;
+  bool frontFrameReady = IsFrontReady();
 
   for( unsigned int i=0; i< mBatchSize && !mQueue.IsFull(); ++i )
   {
 
   for( unsigned int i=0; i< mBatchSize && !mQueue.IsFull(); ++i )
   {
index a0d734d..47a5155 100644 (file)
@@ -60,6 +60,12 @@ public:
   virtual ~RollingImageCache();
 
   /**
   virtual ~RollingImageCache();
 
   /**
+   * Get the Nth frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   */
+  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.
    */
    * Get the first frame. If it's not ready, this will trigger the
    * sending of FrameReady() when the image becomes ready.
    */