[4.0] Loop count support for animated GIF 49/166349/3
authorUmar <m.umar@partner.samsung.com>
Wed, 27 Dec 2017 18:16:57 +0000 (18:16 +0000)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Wed, 10 Jan 2018 11:45:12 +0000 (11:45 +0000)
Change-Id: Ieee7e5441f4c55a69852384b993b6e14ed417ea6

automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-timer.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-timer.h
automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp
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/visual-string-constants.cpp
dali-toolkit/internal/visuals/visual-string-constants.h

index 2259719..aff00f8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
@@ -36,6 +36,7 @@ typedef IntrusivePtr<Timer> TimerPtr;
 
 Dali::Timer::TimerSignalType gTickSignal;
 int gTimerCount = 0;
+bool gKeepTimersRunning = false;
 
 /**
  * Implementation of the timer
@@ -70,6 +71,7 @@ private: // Implementation
 private: // Data
 
   unsigned int mInterval;
+  bool mRunning;
 };
 
 inline Timer& GetImplementation(Dali::Timer& timer)
@@ -97,7 +99,8 @@ TimerPtr Timer::New( unsigned int milliSec )
 }
 
 Timer::Timer( unsigned int milliSec )
-: mInterval( milliSec )
+: mInterval( milliSec ),
+  mRunning( false )
 {
   ++gTimerCount;
 }
@@ -109,10 +112,12 @@ Timer::~Timer()
 
 void Timer::Start()
 {
+  mRunning = true;
 }
 
 void Timer::Stop()
 {
+  mRunning = false;
 }
 
 void Timer::SetInterval( unsigned int interval )
@@ -127,7 +132,7 @@ unsigned int Timer::GetInterval() const
 
 bool Timer::IsRunning() const
 {
-  return true;
+  return mRunning;
 }
 
 bool Timer::Tick()
@@ -151,7 +156,6 @@ void Timer::MockEmitSignal()
   }
 }
 
-
 } // namespace Adaptor
 
 } // namespace Internal
@@ -193,6 +197,7 @@ Timer::~Timer()
 void Timer::Start()
 {
   Internal::Adaptor::GetImplementation( *this ).Start();
+  Dali::Internal::Adaptor::gKeepTimersRunning = true;
 }
 
 void Timer::Stop()
@@ -245,7 +250,13 @@ int GetTimerCount()
 
 void EmitGlobalTimerSignal()
 {
-  Dali::Internal::Adaptor::gTickSignal.Emit();
+  // @todo Multiplex timers properly.
+  Dali::Internal::Adaptor::gKeepTimersRunning = Dali::Internal::Adaptor::gTickSignal.Emit();
+}
+
+bool AreTimersRunning()
+{
+  return Dali::Internal::Adaptor::gKeepTimersRunning;
 }
 
 }
index 0110eaa..544146a 100644 (file)
@@ -2,7 +2,7 @@
 #define __DALI_TOOLKIT_TOOLKIT_TIMER_H__
 
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
@@ -66,6 +66,7 @@ namespace Test
 {
 int GetTimerCount();
 void EmitGlobalTimerSignal();
+bool AreTimersRunning();
 }
 
 #endif // __DALI_TOOLKIT_TOOLKIT_TIMER_H__
index 085ca42..2804868 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
@@ -23,6 +23,7 @@
 #include <dali-toolkit/dali-toolkit.h>
 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
 #include "dummy-control.h"
 
 using namespace Dali;
@@ -118,6 +119,7 @@ int UtcDaliAnimatedImageVisualGetPropertyMap02(void)
     .Add( "url", urls )
     .Add( "batchSize", 4 )
     .Add( "cacheSize", 8 )
+    .Add( "loopCount", 10 )
     .Add( "frameDelay", 200 )
     .Add( "pixelArea", Vector4() )
     .Add( "wrapModeU", WrapMode::REPEAT )
@@ -144,6 +146,10 @@ int UtcDaliAnimatedImageVisualGetPropertyMap02(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_EQUALS( value->Get<int>(), 8, TEST_LOCATION );
 
+  value = resultMap.Find( Toolkit::DevelImageVisual::Property::LOOP_COUNT, "loopCount" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<int>(), 10, TEST_LOCATION );
+
   value = resultMap.Find( ImageVisual::Property::FRAME_DELAY, "frameDelay" );
   DALI_TEST_CHECK( value );
   DALI_TEST_EQUALS( value->Get<int>(), 200, TEST_LOCATION );
@@ -549,3 +555,97 @@ int UtcDaliAnimatedImageVisualMultiImage05(void)
 
   END_TEST;
 }
+
+void TestLoopCount( ToolkitTestApplication &application, DummyControl &dummyControl, uint16_t frameCount, uint16_t loopCount, const char * location )
+{
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+
+  textureTrace.Enable(true);
+  Stage::GetCurrent().Add( dummyControl );
+  application.SendNotification();
+  application.Render(16);
+
+  tet_infoline( "Test that a timer has been created" );
+  DALI_TEST_EQUALS( Test::GetTimerCount(), 1, TEST_INNER_LOCATION( location ) );
+
+  for ( uint16_t i = 0; i <= loopCount; i++ )
+  {
+    for ( uint16_t j = 0; j < frameCount; j++ )
+    {
+      tet_printf( "Test that after %u ticks, and we have %u frame \n", j + 1u, j + 1u );
+      Test::EmitGlobalTimerSignal();
+      application.SendNotification();
+      application.Render(16);
+      DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 1, TEST_INNER_LOCATION( location ) );
+      DALI_TEST_EQUALS( Test::AreTimersRunning(), true, TEST_INNER_LOCATION( location ) );
+    }
+    tet_printf( "\nTest Loop %u \n", i );
+  }
+
+  tet_printf( "Test that after %u loops, and we have no frame. Timer should stop \n", loopCount );
+  Test::EmitGlobalTimerSignal();
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_EQUALS( Test::AreTimersRunning(), false, TEST_INNER_LOCATION( location ) );
+
+  dummyControl.Unparent();
+}
+
+int UtcDaliAnimatedImageVisualLoopCount(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliAnimatedImageVisualLoopCount" );
+
+  {
+    // request AnimatedImageVisual with a property map
+    // Test with no (0) loop count
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base animatedImageVisual = factory.CreateVisual(
+      Property::Map()
+      .Add( Toolkit::Visual::Property::TYPE, Visual::ANIMATED_IMAGE )
+      .Add( ImageVisual::Property::URL, TEST_GIF_FILE_NAME )
+      .Add( ImageVisual::Property::PIXEL_AREA, Vector4() )
+      .Add( ImageVisual::Property::WRAP_MODE_U, WrapMode::REPEAT )
+      .Add( ImageVisual::Property::WRAP_MODE_V, WrapMode::DEFAULT )
+      .Add( DevelImageVisual::Property::LOOP_COUNT, 0 ));
+
+    DummyControl dummyControl = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, animatedImageVisual );
+    dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+
+    TestLoopCount( application, dummyControl, 4, 0, TEST_LOCATION );
+
+    // Test with no (1) loop count. Request AnimatedImageVisual with a property map
+    animatedImageVisual = factory.CreateVisual(
+      Property::Map()
+      .Add( Toolkit::Visual::Property::TYPE, Visual::ANIMATED_IMAGE )
+      .Add( ImageVisual::Property::URL, TEST_GIF_FILE_NAME )
+      .Add( ImageVisual::Property::PIXEL_AREA, Vector4() )
+      .Add( ImageVisual::Property::WRAP_MODE_U, WrapMode::REPEAT )
+      .Add( ImageVisual::Property::WRAP_MODE_V, WrapMode::DEFAULT )
+      .Add( DevelImageVisual::Property::LOOP_COUNT, 1 ));
+
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, animatedImageVisual );
+
+    TestLoopCount( application, dummyControl, 4, 1, TEST_LOCATION );
+
+    // Test with no (100) loop count. Request AnimatedImageVisual with a property map
+    animatedImageVisual = factory.CreateVisual(
+      Property::Map()
+      .Add( Toolkit::Visual::Property::TYPE, Visual::ANIMATED_IMAGE )
+      .Add( ImageVisual::Property::URL, TEST_GIF_FILE_NAME )
+      .Add( ImageVisual::Property::PIXEL_AREA, Vector4() )
+      .Add( ImageVisual::Property::WRAP_MODE_U, WrapMode::REPEAT )
+      .Add( ImageVisual::Property::WRAP_MODE_V, WrapMode::DEFAULT )
+      .Add( DevelImageVisual::Property::LOOP_COUNT, 100 ));
+
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, animatedImageVisual );
+
+    TestLoopCount( application, dummyControl, 4, 100, TEST_LOCATION );
+  }
+
+  END_TEST;
+}
\ No newline at end of file
index a340755..b007485 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_DEVEL_API_VISUALS_IMAGE_VISUAL_PROPERTIES_DEVEL_H
 
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
@@ -76,6 +76,13 @@ enum Type
    */
   AUXILIARY_IMAGE_ALPHA = ORIENTATION_CORRECTION + 2,
 
+  /**
+   * @brief The number of times the AnimatedImageVisual will be looped.
+   * @details Name "loopCount", type Property::INTEGER.
+   * @note For Animated images only. Default -1. if < 0, loop unlimited. else, loop loopCount times.
+   */
+  LOOP_COUNT = ORIENTATION_CORRECTION + 3,
+
 };
 
 } //namespace Property
index 84ae1c9..d37863e 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
@@ -57,6 +57,7 @@ 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;
 
 #if defined(DEBUG_ENABLED)
 Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ANIMATED_IMAGE");
@@ -171,6 +172,8 @@ AnimatedImageVisual::AnimatedImageVisual( VisualFactoryCache& factoryCache )
   mCacheSize( 1 ),
   mBatchSize( 1 ),
   mFrameDelay( 100 ),
+  mLoopCount( LOOP_FOREVER ),
+  mCurrentLoopIndex( 0 ),
   mUrlIndex( 0 ),
   mFrameCount( 0 ),
   mImageSize(),
@@ -231,6 +234,7 @@ void AnimatedImageVisual::DoCreatePropertyMap( Property::Map& map ) const
   map.Insert( Toolkit::ImageVisual::Property::BATCH_SIZE, static_cast<int>(mBatchSize) );
   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) );
 }
 
 void AnimatedImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
@@ -275,6 +279,10 @@ void AnimatedImageVisual::DoSetProperties( const Property::Map& propertyMap )
       {
         DoSetProperty( Toolkit::ImageVisual::Property::FRAME_DELAY, keyValue.second );
       }
+      else if( keyValue.first == LOOP_COUNT_NAME )
+      {
+        DoSetProperty( Toolkit::DevelImageVisual::Property::LOOP_COUNT, keyValue.second );
+      }
     }
   }
 }
@@ -345,6 +353,16 @@ void AnimatedImageVisual::DoSetProperty( Property::Index index,
       }
       break;
     }
+
+    case Toolkit::DevelImageVisual::Property::LOOP_COUNT:
+    {
+      int loopCount;
+      if( value.Get( loopCount ) )
+      {
+        mLoopCount = loopCount;
+      }
+      break;
+    }
   }
 }
 
@@ -547,7 +565,20 @@ bool AnimatedImageVisual::DisplayNextFrame()
   {
     // Wrap the frame index
     ++mCurrentFrameIndex;
-    mCurrentFrameIndex %= mFrameCount;
+
+    if( mLoopCount < 0 || mCurrentLoopIndex <= mLoopCount)
+    {
+      mCurrentFrameIndex %= mFrameCount;
+      if( mCurrentFrameIndex == 0 )
+      {
+        ++mCurrentLoopIndex;
+      }
+    }
+    else
+    {
+      // This will stop timer
+      return false;
+    }
   }
   DALI_LOG_INFO( gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::DisplayNextFrame(this:%p) FrameCount:%d\n", this, mCurrentFrameIndex);
 
index 5c9b31c..e92c5ef 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_ANIMATED_IMAGE_VISUAL_H
 
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
@@ -242,6 +242,8 @@ private:
   uint16_t mCacheSize;
   uint16_t mBatchSize;
   uint16_t mFrameDelay;
+  int16_t mLoopCount;
+  int16_t mCurrentLoopIndex;
   uint16_t mUrlIndex;
 
   // Shared variables
index 079141d..6c6f03c 100644 (file)
@@ -88,6 +88,7 @@ const char * const ANIMATED_IMAGE_URLS_NAME("urls");
 const char * const BATCH_SIZE_NAME("batchSize");
 const char * const CACHE_SIZE_NAME("cacheSize");
 const char * const FRAME_DELAY_NAME("frameDelay");
+const char * const LOOP_COUNT_NAME("loopCount");
 const char * const MASK_CONTENT_SCALE_NAME("maskContentScale");
 const char * const CROP_TO_MASK_NAME("cropToMask");
 const char * const LOAD_POLICY_NAME("loadPolicy");
index 1a73da9..f1fe499 100644 (file)
@@ -74,6 +74,7 @@ extern const char * const ANIMATED_IMAGE_URLS_NAME;
 extern const char * const BATCH_SIZE_NAME;
 extern const char * const CACHE_SIZE_NAME;
 extern const char * const FRAME_DELAY_NAME;
+extern const char * const LOOP_COUNT_NAME;
 extern const char * const MASK_CONTENT_SCALE_NAME;
 extern const char * const CROP_TO_MASK_NAME;
 extern const char * const LOAD_POLICY_NAME;