Merge "Divide Render() into small apis" into devel/master
authorjoogab yun <joogab.yun@samsung.com>
Mon, 13 Jul 2020 01:17:01 +0000 (01:17 +0000)
committerGerrit Code Review <gerrit@review>
Mon, 13 Jul 2020 01:17:01 +0000 (01:17 +0000)
23 files changed:
automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp
automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-ScrollBar.cpp
automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp
dali-toolkit/devel-api/image-loader/async-image-loader-devel.cpp
dali-toolkit/devel-api/image-loader/async-image-loader-devel.h
dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.cpp
dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.h
dali-toolkit/internal/image-loader/async-image-loader-impl.cpp
dali-toolkit/internal/image-loader/async-image-loader-impl.h
dali-toolkit/internal/image-loader/image-load-thread.cpp
dali-toolkit/internal/image-loader/image-load-thread.h
dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp
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/image/image-visual.cpp
dali-toolkit/internal/visuals/npatch/npatch-visual.cpp
dali-toolkit/internal/visuals/texture-manager-impl.cpp
dali-toolkit/internal/visuals/texture-manager-impl.h
dali-toolkit/public-api/dali-toolkit-version.cpp
dali-toolkit/public-api/visuals/image-visual-properties.h
packaging/dali-toolkit.spec

index bad5ea0..59be4f2 100644 (file)
@@ -158,6 +158,105 @@ int UtcDaliAnimatedImageVisualGetPropertyMap02(void)
   END_TEST;
 }
 
+int UtcDaliAnimatedImageVisualGetPropertyMap03(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedImageVisualGetPropertyMap" );
+
+  // request AnimatedImageVisual with a property map
+  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::BATCH_SIZE, 1 )
+    .Add( ImageVisual::Property::CACHE_SIZE, 1 )
+    .Add( ImageVisual::Property::SYNCHRONOUS_LOADING, false ));
+
+  Property::Map resultMap;
+  animatedImageVisual.CreatePropertyMap( resultMap );
+
+  // check the property values from the returned map from a visual
+  Property::Value* value = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == Visual::ANIMATED_IMAGE );
+
+  value = resultMap.Find( ImageVisual::Property::URL,  Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<std::string>() == TEST_GIF_FILE_NAME );
+
+  value = resultMap.Find( ImageVisual::Property::BATCH_SIZE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == 2 );
+
+  value = resultMap.Find( ImageVisual::Property::CACHE_SIZE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == 2 );
+
+  END_TEST;
+}
+
+
+int UtcDaliAnimatedImageVisualSynchronousLoading(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, 2);
+    propertyMap.Insert( ImageVisual::Property::FRAME_DELAY, 20);
+    propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, true);
+
+    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 );
+
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    application.SendNotification();
+    application.Render(20);
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 2 ), true, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( Test::GetTimerCount(), 1, TEST_LOCATION );
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 2, TEST_LOCATION );
+
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::JUMP_TO, 3 );
+
+    application.SendNotification();
+    application.Render(20);
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 2 ), true, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 3, 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 UtcDaliAnimatedImageVisualJumpToAction(void)
 {
@@ -318,6 +417,12 @@ int UtcDaliAnimatedImageVisualAnimatedImage01(void)
 
     dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
     Stage::GetCurrent().Add( dummyControl );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 2 ), true, TEST_LOCATION );
+
     application.SendNotification();
     application.Render(20);
 
@@ -331,6 +436,11 @@ int UtcDaliAnimatedImageVisualAnimatedImage01(void)
     Test::EmitGlobalTimerSignal();
 
     application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 2 ), true, TEST_LOCATION );
+
+    application.SendNotification();
     application.Render(20);
 
     DALI_TEST_EQUALS( gl.GetLastGenTextureId(), 4, TEST_LOCATION );
@@ -452,8 +562,8 @@ int UtcDaliAnimatedImageVisualMultiImage02(void)
     Property::Map propertyMap;
     propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE );
     propertyMap.Insert( ImageVisual::Property::URL, Property::Value(urls) );
-    propertyMap.Insert( ImageVisual::Property::BATCH_SIZE, 0);
-    propertyMap.Insert( ImageVisual::Property::CACHE_SIZE, 0);
+    propertyMap.Insert( ImageVisual::Property::BATCH_SIZE, 2);
+    propertyMap.Insert( ImageVisual::Property::CACHE_SIZE, 2);
     propertyMap.Insert( ImageVisual::Property::FRAME_DELAY, 100);
 
     VisualFactory factory = VisualFactory::Get();
@@ -749,9 +859,15 @@ void TestLoopCount( ToolkitTestApplication &application, DummyControl &dummyCont
 
   textureTrace.Enable(true);
   Stage::GetCurrent().Add( dummyControl );
+
   application.SendNotification();
   application.Render(16);
 
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 2 ), true, TEST_INNER_LOCATION( location ) );
+
+  application.SendNotification();
+  application.Render();
+
   tet_infoline( "Test that a timer has been created" );
   DALI_TEST_EQUALS( Test::GetTimerCount(), 1, TEST_INNER_LOCATION( location ) );
 
@@ -767,10 +883,15 @@ void TestLoopCount( ToolkitTestApplication &application, DummyControl &dummyCont
       Test::EmitGlobalTimerSignal();
       application.SendNotification();
       application.Render(16);
-      DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 1, TEST_INNER_LOCATION( location ) );
+
+      DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_INNER_LOCATION( location ) );
+
+      application.SendNotification();
+      application.Render();
+      DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 2, TEST_INNER_LOCATION( location ) );
       DALI_TEST_EQUALS( Test::AreTimersRunning(), true, TEST_INNER_LOCATION( location ) );
     }
-    tet_printf( "\nTest Loop %u \n", i );
+    tet_printf( "Test Loop %u \n\n", i + 1u );
   }
 
   tet_printf( "Test that after %u loops, and we have no frame. Timer should stop \n", loopCount );
@@ -808,6 +929,12 @@ int UtcDaliAnimatedImageVisualLoopCount(void)
 
     TestLoopCount( application, dummyControl, 4, 0, TEST_LOCATION );
 
+    dummyImpl.UnregisterVisual( DummyControl::Property::TEST_VISUAL );
+    animatedImageVisual.Reset();
+
+    application.SendNotification();
+    application.Render(16);
+
     // Test with no (1) loop count. Request AnimatedImageVisual with a property map
     animatedImageVisual = factory.CreateVisual(
       Property::Map()
@@ -822,6 +949,12 @@ int UtcDaliAnimatedImageVisualLoopCount(void)
 
     TestLoopCount( application, dummyControl, 4, 1, TEST_LOCATION );
 
+    dummyImpl.UnregisterVisual( DummyControl::Property::TEST_VISUAL );
+    animatedImageVisual.Reset();
+
+    application.SendNotification();
+    application.Render(16);
+
     // Test with no (100) loop count. Request AnimatedImageVisual with a property map
     animatedImageVisual = factory.CreateVisual(
       Property::Map()
@@ -836,7 +969,6 @@ int UtcDaliAnimatedImageVisualLoopCount(void)
 
     TestLoopCount( application, dummyControl, 4, 100, TEST_LOCATION );
   }
-
   END_TEST;
 }
 
@@ -871,12 +1003,22 @@ int UtcDaliAnimatedImageVisualPlayback(void)
     application.SendNotification();
     application.Render(16);
 
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 2 ), true, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render();
+
     tet_infoline( "Test that a timer has been created" );
     DALI_TEST_EQUALS( Test::GetTimerCount(), 1, TEST_LOCATION );
 
     Test::EmitGlobalTimerSignal();
     application.SendNotification();
     application.Render(16);
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render();
     DALI_TEST_EQUALS( Test::AreTimersRunning(), true, TEST_LOCATION );
 
     Property::Map attributes;
@@ -892,6 +1034,11 @@ int UtcDaliAnimatedImageVisualPlayback(void)
     Test::EmitGlobalTimerSignal();
     application.SendNotification();
     application.Render(16);
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render();
     DALI_TEST_EQUALS( Test::AreTimersRunning(), true, TEST_LOCATION );
 
     tet_infoline( "Test Stop action. Timer should stop after Stop action" );
@@ -906,6 +1053,11 @@ int UtcDaliAnimatedImageVisualPlayback(void)
     Test::EmitGlobalTimerSignal();
     application.SendNotification();
     application.Render(16);
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render();
     DALI_TEST_EQUALS( Test::AreTimersRunning(), true, TEST_LOCATION );
 
     dummyControl.Unparent();
index d7aa177..7ece9d3 100644 (file)
@@ -424,6 +424,11 @@ int UtcDaliImageViewPixelArea(void)
   // loading started
   application.SendNotification();
   application.Render(16);
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 2 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
   DALI_TEST_CHECK( gifView.GetRendererCount() == 1u );
 
   const Vector4 fullTextureRect( 0.f, 0.f, 1.f, 1.f );
@@ -861,6 +866,11 @@ int UtcDaliImageViewCheckResourceReady(void)
   application.SendNotification();
   application.Render(16);
 
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 2 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
   DALI_TEST_EQUALS( imageView.IsResourceReady(), true, TEST_LOCATION );
 
   DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
index 78792d9..d34f665 100644 (file)
@@ -1098,7 +1098,7 @@ int UtcDaliImageVisualTextureCancelRemoteLoad(void)
 int UtcDaliImageVisualTextureCancelAsyncLoad(void)
 {
   ToolkitTestApplication application;
-  tet_infoline( "Load image asynchronosly, cancel loading, then load again" );
+  tet_infoline( "Load image asynchronously, cancel loading, then load again" );
 
   VisualFactory factory = VisualFactory::Get();
   DALI_TEST_CHECK( factory );
@@ -1861,6 +1861,87 @@ int UtcDaliImageVisualReleasePolicy07(void)
   END_TEST;
 }
 
+int UtcDaliImageVisualReleasePolicy08(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualReleasePolicy08 Ensure TextureSet is same after detach/attach on stage when texture used the DESTROYED release policy" );
+
+  tet_infoline( "Create first visual with DESTROYED release policy" );
+  Visual::Base imageVisualDestroyed = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, ImageVisual::Property::RELEASE_POLICY, ImageVisual::ReleasePolicy::DESTROYED );
+
+  // Set up trace debug
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  tet_infoline( "Register visuals with control and ensure it has the only handles" );
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisualDestroyed );
+  imageVisualDestroyed.Reset(); // reduce ref count so only the control keeps the visual alive.
+
+  actor.SetProperty( Actor::Property::SIZE, Vector2(200.f, 200.f) );
+
+  // Test initially zero renderers
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+  textureTrace.Reset();
+
+  Stage::GetCurrent().Add( actor );
+
+  // Wait for image to load
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render(0);
+  tet_infoline( "Ensure a texture is created" );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
+
+  // Ensure TextureSet is same after detach/attach on stage when texture used the DESTROYED release policy
+  // 1. Get TextureSet
+  TextureSet textureSetBefore = actor.GetRendererAt( 0u ).GetTextures();
+
+  // 2.Remove actor from stage. In this case, renderer also is deleted.
+  tet_infoline( "Remove actor from stage" );
+  Stage::GetCurrent().Remove( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure a texture is not deleted as visual used the DESTROYED release policy" );
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION );
+  textureTrace.Reset();
+
+  // 3.Add actor in stage. In this case, renderer is created.
+  tet_infoline( "Add actor in stage" );
+  Stage::GetCurrent().Add( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  application.SendNotification();
+  application.Render();
+  tet_infoline( "Ensure a texture is not created again" );
+  DALI_TEST_EQUALS( textureTrace.CountMethod("GenTextures"), 0, TEST_LOCATION );
+  textureTrace.Reset();
+
+  // 4.Compare Texture with before and after. textureSet need to be same because release policy is the DESTROYED.
+  tet_infoline( "Ensure a textureSet is not deleted because it is used the DESTROYED release policy" );
+  TextureSet textureSetAfter = actor.GetRendererAt( 0u ).GetTextures();
+  DALI_TEST_CHECK( textureSetBefore == textureSetAfter );
+  textureSetBefore.Reset();
+  textureSetAfter.Reset();
+
+  dummyImpl.UnregisterVisual( DummyControl::Property::TEST_VISUAL );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 1, TEST_LOCATION );
+
+  END_TEST;
+}
+
 int UtcDaliImageVisualLoadPolicy01(void)
 {
   ToolkitTestApplication application;
index 1d32e33..609621a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -19,6 +19,7 @@
 #include <stdlib.h>
 #include <string>
 #include <dali-toolkit-test-suite-utils.h>
+#include "dali-toolkit-test-utils/toolkit-timer.h"
 #include <dali-toolkit/dali-toolkit.h>
 #include <dali/devel-api/actors/actor-devel.h>
 #include <dali-toolkit/devel-api/controls/scroll-bar/scroll-bar.h>
@@ -116,6 +117,8 @@ static Vector2 PerformGestureSwipe(ToolkitTestApplication& application, Vector2
 
   for(int i = 0; i < frames; i++)
   {
+    Test::EmitGlobalTimerSignal();
+
     pos += direction; // Move in this direction
     time += RENDER_FRAME_INTERVAL;
     TestMovePan( application, pos, time);
index c78d090..bad210c 100644 (file)
@@ -2048,6 +2048,11 @@ int UtcDaliVisualFactoryGetAnimatedImageVisual1(void)
   application.SendNotification();
   application.Render();
 
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 2 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
   // renderer is added to actor
   DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
   Renderer renderer = actor.GetRendererAt( 0u );
@@ -2061,14 +2066,23 @@ int UtcDaliVisualFactoryGetAnimatedImageVisual1(void)
   timer.MockEmitSignal();
   application.SendNotification();
   application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
   DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
   textureTrace.Reset();
 
-
   // Force the timer used by the animatedImageVisual to tick,
   timer.MockEmitSignal();
   application.SendNotification();
   application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
   DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
   textureTrace.Reset();
 
@@ -2076,6 +2090,11 @@ int UtcDaliVisualFactoryGetAnimatedImageVisual1(void)
   timer.MockEmitSignal();
   application.SendNotification();
   application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
   DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
   textureTrace.Reset();
 
@@ -2117,6 +2136,11 @@ int UtcDaliVisualFactoryGetAnimatedImageVisual2(void)
   application.SendNotification();
   application.Render();
 
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 2 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
   DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
 
   DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
index 5fc985f..e9b7744 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -24,6 +24,13 @@ namespace Toolkit
 namespace DevelAsyncImageLoader
 {
 
+uint32_t LoadAnimatedImage( AsyncImageLoader asyncImageLoader,
+                            Dali::AnimatedImageLoading animatedImageLoading,
+                            uint32_t frameIndex )
+{
+  return GetImplementation( asyncImageLoader ).LoadAnimatedImage( animatedImageLoading, frameIndex );
+}
+
 uint32_t Load( AsyncImageLoader asyncImageLoader,
                const std::string& url,
                ImageDimensions dimensions,
index 99ca154..a6732df 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_DEVEL_API_IMAGE_LOADER_ASYNC_IMAGE_LOADER_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.
  * limitations under the License.
  */
 
+// EXTERNAL HEADER
 #include <dali/public-api/signals/dali-signal.h>
 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/devel-api/adaptor-framework/animated-image-loading.h>
+
+// INTERNAL HEADER
 #include <dali-toolkit/public-api/image-loader/async-image-loader.h>
 
 namespace Dali
@@ -40,6 +44,19 @@ enum class PreMultiplyOnLoad
 };
 
 /**
+ * @brief Starts an animated image loading task.
+ * @REMARK_INTERNET
+ * @REMARK_STORAGE
+ * @param[in] asyncImageLoader The ayncImageLoader
+ * @param[in] animatedImageLoading The AnimatedImageLoading to load animated image
+ * @param[in] frameIndex The frame index of a frame to be loaded frame
+ * @return The loading task id
+ */
+DALI_TOOLKIT_API uint32_t LoadAnimatedImage( AsyncImageLoader asyncImageLoader,
+                                             Dali::AnimatedImageLoading animatedImageLoading,
+                                             uint32_t frameIndex );
+
+/**
  * @brief Starts an image loading task.
  * @REMARK_INTERNET
  * @REMARK_STORAGE
index 711f323..7056b0c 100755 (executable)
@@ -186,7 +186,7 @@ ScrollBar::ScrollBar(Toolkit::ScrollBar::Direction direction)
 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
   mIndicatorShowAlpha(1.0f),
   mDirection(direction),
-  mScrollableObject(WeakHandleBase()),
+  mScrollableObject(WeakHandle<Handle>()),
   mPropertyScrollPosition(Property::INVALID_INDEX),
   mPropertyMinScrollPosition(Property::INVALID_INDEX),
   mPropertyMaxScrollPosition(Property::INVALID_INDEX),
@@ -225,7 +225,7 @@ void ScrollBar::SetScrollPropertySource( Handle handle, Property::Index property
       && propertyMaxScrollPosition != Property::INVALID_INDEX
       && propertyScrollContentSize != Property::INVALID_INDEX )
   {
-    mScrollableObject = WeakHandleBase(handle);
+    mScrollableObject = WeakHandle<Handle>(handle);
     mPropertyScrollPosition = propertyScrollPosition;
     mPropertyMinScrollPosition = propertyMinScrollPosition;
     mPropertyMaxScrollPosition = propertyMaxScrollPosition;
@@ -294,7 +294,7 @@ Actor ScrollBar::GetScrollIndicator()
 
 void ScrollBar::ApplyConstraints()
 {
-  Handle scrollableHandle = mScrollableObject.GetBaseHandle();
+  Handle scrollableHandle = mScrollableObject.GetHandle();
 
   if( scrollableHandle )
   {
@@ -337,7 +337,7 @@ void ScrollBar::SetScrollPositionIntervals( const Dali::Vector<float>& positions
 {
   mScrollPositionIntervals = positions;
 
-  Handle scrollableHandle = mScrollableObject.GetBaseHandle();
+  Handle scrollableHandle = mScrollableObject.GetHandle();
 
   if( scrollableHandle )
   {
@@ -359,7 +359,7 @@ Dali::Vector<float> ScrollBar::GetScrollPositionIntervals() const
 void ScrollBar::OnScrollPositionIntervalReached(PropertyNotification& source)
 {
   // Emit the signal to notify the scroll position crossing
-  Handle scrollableHandle = mScrollableObject.GetBaseHandle();
+  Handle scrollableHandle = mScrollableObject.GetHandle();
   if(scrollableHandle)
   {
     mScrollPositionIntervalReachedSignal.Emit( scrollableHandle.GetCurrentProperty< float >( mPropertyScrollPosition ) );
@@ -442,7 +442,7 @@ void ScrollBar::ShowTransientIndicator()
 bool ScrollBar::OnPanGestureProcessTick()
 {
   // Update the scroll position property.
-  Handle scrollableHandle = mScrollableObject.GetBaseHandle();
+  Handle scrollableHandle = mScrollableObject.GetHandle();
   if( scrollableHandle )
   {
     scrollableHandle.SetProperty(mPropertyScrollPosition, mCurrentScrollPosition);
@@ -453,7 +453,7 @@ bool ScrollBar::OnPanGestureProcessTick()
 
 void ScrollBar::OnPan( const PanGesture& gesture )
 {
-  Handle scrollableHandle = mScrollableObject.GetBaseHandle();
+  Handle scrollableHandle = mScrollableObject.GetHandle();
 
   if(scrollableHandle)
   {
index e808d83..f56b9a0 100755 (executable)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_SCROLL_BAR_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.
@@ -283,7 +283,7 @@ private:
 
   Toolkit::ScrollBar::Direction mDirection;                          ///< The direction of scroll bar (vertical or horizontal)
 
-  WeakHandleBase mScrollableObject;                                  ///< Object to be scrolled
+  WeakHandle<Handle> mScrollableObject;                              ///< Object to be scrolled
 
   Property::Index mPropertyScrollPosition;                           ///< Index of scroll position property owned by the object to be scrolled
   Property::Index mPropertyMinScrollPosition;                        ///< Index of minimum scroll position property owned by the object to be scrolled
index 6fe8eba..912a441 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -49,6 +49,19 @@ IntrusivePtr<AsyncImageLoader> AsyncImageLoader::New()
   return internal;
 }
 
+uint32_t AsyncImageLoader::LoadAnimatedImage( Dali::AnimatedImageLoading animatedImageLoading,
+                                              uint32_t frameIndex )
+{
+  if( !mIsLoadThreadStarted )
+  {
+    mLoadThread.Start();
+    mIsLoadThreadStarted = true;
+  }
+  mLoadThread.AddTask( new LoadingTask( ++mLoadTaskId, animatedImageLoading, frameIndex ) );
+
+  return mLoadTaskId;
+}
+
 uint32_t AsyncImageLoader::Load( const VisualUrl& url,
                                  ImageDimensions dimensions,
                                  FittingMode::Type fittingMode,
index a97088d..e49b146 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_ASYNC_IMAGE_LOADER_IMPL_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.
@@ -50,6 +50,12 @@ public:
   static IntrusivePtr<AsyncImageLoader> New();
 
   /**
+   * @copydoc Toolkit::AsyncImageLoader::LoadAnimatedImage( Dali::AnimatedImageLoading animatedImageLoading, uint32_t frameIndex )
+   */
+  uint32_t LoadAnimatedImage( Dali::AnimatedImageLoading animatedImageLoading,
+                              uint32_t frameIndex );
+
+  /**
    * @copydoc Toolkit::AsyncImageLoader::Load( const std::string&, ImageDimensions, FittingMode::Type, SamplingMode::Type, bool , DevelAsyncImageLoader::PreMultiplyOnLoad )
    */
   uint32_t Load( const VisualUrl& url,
index 179734a..dae742d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -33,6 +33,24 @@ namespace Toolkit
 namespace Internal
 {
 
+LoadingTask::LoadingTask( uint32_t id, Dali::AnimatedImageLoading animatedImageLoading, uint32_t frameIndex )
+: pixelBuffer(),
+  url(),
+  id( id ),
+  dimensions(),
+  fittingMode(),
+  samplingMode(),
+  orientationCorrection(),
+  preMultiplyOnLoad( DevelAsyncImageLoader::PreMultiplyOnLoad::OFF ),
+  isMaskTask( false ),
+  maskPixelBuffer(),
+  contentScale( 1.0f ),
+  cropToMask( false ),
+  animatedImageLoading( animatedImageLoading ),
+  frameIndex( frameIndex )
+{
+}
+
 LoadingTask::LoadingTask( uint32_t id, const VisualUrl& url, ImageDimensions dimensions,
                           FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad )
 : pixelBuffer(),
@@ -46,7 +64,9 @@ LoadingTask::LoadingTask( uint32_t id, const VisualUrl& url, ImageDimensions dim
   isMaskTask( false ),
   maskPixelBuffer(),
   contentScale( 1.0f ),
-  cropToMask( false )
+  cropToMask( false ),
+  animatedImageLoading(),
+  frameIndex( 0u )
 {
 }
 
@@ -63,13 +83,19 @@ LoadingTask::LoadingTask( uint32_t id, Devel::PixelBuffer pixelBuffer, Devel::Pi
   isMaskTask( true ),
   maskPixelBuffer( maskPixelBuffer ),
   contentScale( contentScale ),
-  cropToMask( cropToMask )
+  cropToMask( cropToMask ),
+  animatedImageLoading(),
+  frameIndex( 0u )
 {
 }
 
 void LoadingTask::Load()
-{
-  if( url.IsLocalResource() )
+{;
+  if( animatedImageLoading )
+  {
+    pixelBuffer = animatedImageLoading.LoadFrame( frameIndex );
+  }
+  else if( url.IsLocalResource() )
   {
     pixelBuffer = Dali::LoadImageFromFile( url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection );
   }
@@ -140,7 +166,6 @@ void ImageLoadThread::Run()
 void ImageLoadThread::AddTask( LoadingTask* task )
 {
   bool wasEmpty = false;
-
   {
     // Lock while adding task to the queue
     ConditionalWait::ScopedLock lock( mConditionalWait );
index 779541a..b435611 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_IMAGE_LOAD_THREAD_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.
@@ -47,6 +47,16 @@ struct LoadingTask
   /**
    * Constructor.
    * @param [in] id of the task
+   * @param [in] animatedImageLoading The AnimatedImageLoading to load animated image
+   * @param [in] frameIndex The frame index of a frame to be loaded frame
+   */
+  LoadingTask( uint32_t id,
+               Dali::AnimatedImageLoading animatedImageLoading,
+               uint32_t frameIndex );
+
+  /**
+   * Constructor.
+   * @param [in] id of the task
    * @param [in] url The URL of the image file to load.
    * @param [in] size The width and height to fit the loaded image to, 0.0 means whole image
    * @param [in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter.
@@ -60,7 +70,7 @@ struct LoadingTask
                FittingMode::Type fittingMode,
                SamplingMode::Type samplingMode,
                bool orientationCorrection,
-               DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad);
+               DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad );
 
   /**
    * Constructor.
@@ -72,11 +82,11 @@ struct LoadingTask
    * @param [in] preMultiplyOnLoad ON if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha.
    */
   LoadingTask( uint32_t id,
-              Devel::PixelBuffer pixelBuffer,
-              Devel::PixelBuffer maskPixelBuffer,
-              float contentScale,
-              bool cropToMask,
-              DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad);
+               Devel::PixelBuffer pixelBuffer,
+               Devel::PixelBuffer maskPixelBuffer,
+               float contentScale,
+               bool cropToMask,
+               DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad );
 
   /**
    * Load the image
@@ -117,6 +127,8 @@ public:
   Devel::PixelBuffer maskPixelBuffer; ///< pixelBuffer of mask image
   float contentScale;               ///< The factor to scale the content
   bool cropToMask;                  ///< Whether to crop the content to the mask size
+  Dali::AnimatedImageLoading animatedImageLoading;
+  uint32_t frameIndex;
 };
 
 
index fdde260..6b7adf3 100755 (executable)
@@ -177,8 +177,8 @@ AnimatedImageVisual::AnimatedImageVisual( VisualFactoryCache& factoryCache, Imag
   mCurrentFrameIndex( 0 ),
   mImageUrls( NULL ),
   mImageCache( NULL ),
-  mCacheSize( 1 ),
-  mBatchSize( 1 ),
+  mCacheSize( 2 ),
+  mBatchSize( 2 ),
   mFrameDelay( 100 ),
   mLoopCount( LOOP_FOREVER ),
   mCurrentLoopIndex( 0 ),
@@ -221,6 +221,9 @@ void AnimatedImageVisual::DoCreatePropertyMap( Property::Map& map ) const
 {
   map.Clear();
 
+  bool sync = IsSynchronousLoadingRequired();
+  map.Insert( Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, sync );
+
   map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::ANIMATED_IMAGE );
 
   if( mImageUrl.IsValid() )
@@ -402,7 +405,14 @@ void AnimatedImageVisual::DoSetProperty( Property::Index index,
       int batchSize;
       if( value.Get( batchSize ) )
       {
-        mBatchSize = batchSize;
+        if( batchSize < 2 )
+        {
+          DALI_LOG_ERROR( "The minimum value of batch size is 2." );
+        }
+        else
+        {
+          mBatchSize = batchSize;
+        }
       }
       break;
     }
@@ -412,7 +422,14 @@ void AnimatedImageVisual::DoSetProperty( Property::Index index,
       int cacheSize;
       if( value.Get( cacheSize ) )
       {
-        mCacheSize = cacheSize;
+        if( cacheSize < 2 )
+        {
+          DALI_LOG_ERROR( "The minimum value of cache size is 2." );
+        }
+        else
+        {
+          mCacheSize = cacheSize;
+        }
       }
       break;
     }
@@ -446,6 +463,21 @@ void AnimatedImageVisual::DoSetProperty( Property::Index index,
       }
       break;
     }
+
+    case Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING:
+    {
+      bool sync = false;
+      value.Get( sync );
+      if( sync )
+      {
+        mImpl->mFlags |= Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
+      }
+      else
+      {
+        mImpl->mFlags &= ~Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
+      }
+      break;
+    }
   }
 }
 
@@ -543,7 +575,7 @@ void AnimatedImageVisual::LoadFirstBatch()
 
   if( mAnimatedImageLoading )
   {
-    mImageCache = new RollingAnimatedImageCache( textureManager, mAnimatedImageLoading, mFrameCount, *this, cacheSize, batchSize );
+    mImageCache = new RollingAnimatedImageCache( textureManager, mAnimatedImageLoading, mFrameCount, *this, cacheSize, batchSize, IsSynchronousLoadingRequired() );
   }
   else if( mImageUrls )
   {
@@ -607,14 +639,16 @@ TextureSet AnimatedImageVisual::PrepareTextureSet()
 {
   TextureSet textureSet;
   if (mImageCache)
+  {
     textureSet = mImageCache->FirstFrame();
+  }
   if( textureSet )
   {
     SetImageSize( textureSet );
   }
   else
   {
-    DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"ResourceReady(ResourceStatus::FAILED)\n");
+    DALI_LOG_INFO( gAnimImgLogFilter, Debug::Concise, "ResourceReady(ResourceStatus::FAILED)\n" );
     ResourceReady( Toolkit::Visual::ResourceStatus::FAILED );
   }
 
@@ -644,7 +678,7 @@ void AnimatedImageVisual::FrameReady( TextureSet textureSet )
   }
   else
   {
-    if(mImpl->mRenderer)
+    if( mImpl->mRenderer )
     {
       mImpl->mRenderer.SetTextures( textureSet );
     }
index c421678..3992b08 100644 (file)
@@ -60,15 +60,17 @@ namespace Internal
 
 RollingAnimatedImageCache::RollingAnimatedImageCache(
   TextureManager& textureManager, AnimatedImageLoading& animatedImageLoading, uint32_t frameCount, ImageCache::FrameReadyObserver& observer,
-  uint16_t cacheSize, uint16_t batchSize )
+  uint16_t cacheSize, uint16_t batchSize, bool isSynchronousLoading )
 : ImageCache( textureManager, observer, batchSize ),
   mAnimatedImageLoading( animatedImageLoading ),
   mFrameCount( frameCount ),
   mFrameIndex( 0 ),
-  mCacheSize( cacheSize ),
-  mQueue( cacheSize )
+  mQueue( cacheSize ),
+  mIsSynchronousLoading( isSynchronousLoading ),
+  mOnLoading( false )
 {
   mImageUrls.resize( mFrameCount );
+  mIntervals.assign( mFrameCount, 0 );
   LoadBatch();
 }
 
@@ -76,10 +78,10 @@ RollingAnimatedImageCache::~RollingAnimatedImageCache()
 {
   if( mTextureManagerAlive )
   {
-    while( IsFrontReady() )
+    while( !mQueue.IsEmpty() )
     {
       ImageFrame imageFrame = mQueue.PopFront();
-      Dali::Toolkit::TextureManager::RemoveTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl );
+      mTextureManager.Remove( mImageUrls[ imageFrame.mFrameNumber ].mTextureId, this );
     }
   }
 }
@@ -87,29 +89,59 @@ RollingAnimatedImageCache::~RollingAnimatedImageCache()
 TextureSet RollingAnimatedImageCache::Frame( uint32_t frameIndex )
 {
   bool popExist = false;
-  while( IsFrontReady() && mQueue.Front().mFrameNumber != frameIndex )
+  while( !mQueue.IsEmpty() && mQueue.Front().mFrameNumber != frameIndex )
   {
     ImageFrame imageFrame = mQueue.PopFront();
-    Dali::Toolkit::TextureManager::RemoveTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl );
+    mTextureManager.Remove( mImageUrls[ imageFrame.mFrameNumber ].mTextureId, this );
     mImageUrls[ imageFrame.mFrameNumber ].mTextureId = TextureManager::INVALID_TEXTURE_ID;
     popExist = true;
   }
-  if( popExist || mImageUrls[ frameIndex ].mTextureId == TextureManager::INVALID_TEXTURE_ID )
+
+  TextureSet textureSet;
+  // 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;
+  }
+
+  if( popExist || mQueue.IsEmpty() )
   {
     // If the frame of frameIndex was already loaded, load batch from the last frame of queue
-    if( IsFrontReady() )
+    if( !mQueue.IsEmpty() )
     {
       mFrameIndex = ( mQueue.Back().mFrameNumber + 1 ) % mFrameCount;
     }
-    // If the queue is empty, load batch from the frame of frameIndex
     else
     {
-      mFrameIndex = frameIndex;
+      // 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;
+      }
     }
     LoadBatch();
   }
 
-  return GetFrontTextureSet();
+  if( !textureSet )
+  {
+    if( IsFrontReady() == true )
+    {
+      textureSet = GetFrontTextureSet();
+    }
+    else
+    {
+      mWaitingForReadyFrame = true;
+    }
+  }
+
+  return textureSet;
 }
 
 TextureSet RollingAnimatedImageCache::FirstFrame()
@@ -119,13 +151,24 @@ TextureSet RollingAnimatedImageCache::FirstFrame()
 
 uint32_t RollingAnimatedImageCache::GetFrameInterval( uint32_t frameIndex )
 {
-  Frame( frameIndex );
   return mAnimatedImageLoading.GetFrameInterval( frameIndex );
 }
 
 bool RollingAnimatedImageCache::IsFrontReady() const
 {
-  return ( !mQueue.IsEmpty() );
+  return ( !mQueue.IsEmpty() && mQueue.Front().mReady );
+}
+
+void RollingAnimatedImageCache::RequestFrameLoading( uint32_t frameIndex )
+{
+  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 );
+
+  mRequestingLoad = false;
 }
 
 void RollingAnimatedImageCache::LoadBatch()
@@ -134,61 +177,46 @@ void RollingAnimatedImageCache::LoadBatch()
   // Once the cache is filled, as frames progress, the old frame is
   // removed, and another frame is loaded
 
-  std::vector<Dali::PixelData> pixelDataList;
-
-  // Get the smallest number of frames we need to load
-  int batchSize = std::min( std::size_t(mBatchSize), mCacheSize - mQueue.Count() );
-  DALI_LOG_INFO( gAnimImgLogFilter, Debug::Concise, "RollingAnimatedImageCache::LoadBatch() mFrameIndex:%d  batchSize:%d\n", mFrameIndex, batchSize );
-  if( mAnimatedImageLoading.LoadNextNFrames( mFrameIndex, batchSize, pixelDataList) )
+  bool frontFrameReady = IsFrontReady();
+  for( unsigned int i=0; i< mBatchSize && !mQueue.IsFull(); ++i )
   {
-    unsigned int pixelDataListCount = pixelDataList.size();
+    ImageFrame imageFrame;
+    imageFrame.mFrameNumber = mFrameIndex;
+    imageFrame.mReady = false;
 
-    for( unsigned int i = 0; i < pixelDataListCount && !mQueue.IsFull(); ++i )
+    mQueue.PushBack( imageFrame );
+
+    if( !mOnLoading )
     {
-      ImageFrame imageFrame;
-
-      // create the texture for uploading the pixel data
-      Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
-                                      pixelDataList[i].GetPixelFormat(),
-                                      pixelDataList[i].GetWidth(),
-                                      pixelDataList[i].GetHeight() );
-
-      texture.Upload( pixelDataList[i] );
-
-      mImageUrls[ mUrlIndex ].mUrl = Dali::Toolkit::TextureManager::AddTexture(texture);
-      imageFrame.mFrameNumber = mUrlIndex;
-
-      ++mUrlIndex;
-      mUrlIndex %= mImageUrls.size();
-
-      mQueue.PushBack( imageFrame );
-
-      bool synchronousLoading = false;
-      bool atlasingStatus = false;
-      bool loadingStatus = false;
-      TextureManager::MaskingDataPointer maskInfo = nullptr;
-      AtlasUploadObserver* atlasObserver = nullptr;
-      ImageAtlasManagerPtr imageAtlasManager = nullptr;
-      Vector4 textureRect;
-      Dali::ImageDimensions textureRectSize;
-      auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
-
-      mTextureManager.LoadTexture(
-        mImageUrls[ imageFrame.mFrameNumber ].mUrl, ImageDimensions(), FittingMode::SCALE_TO_FILL,
-        SamplingMode::BOX_THEN_LINEAR, maskInfo,
-        synchronousLoading, mImageUrls[ imageFrame.mFrameNumber ].mTextureId, textureRect, textureRectSize,
-        atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT,
-        Dali::WrapMode::Type::DEFAULT, NULL,
-        atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply );
+      mOnLoading = true;
+      RequestFrameLoading( mFrameIndex );
+    }
+    else
+    {
+      mLoadWaitingQueue.push_back( mFrameIndex );
     }
 
-    mFrameIndex += batchSize;
+    mFrameIndex++;
     mFrameIndex %= mFrameCount;
   }
 
+  CheckFrontFrame( frontFrameReady );
+
   LOG_CACHE;
 }
 
+void RollingAnimatedImageCache::SetImageFrameReady( TextureManager::TextureId textureId )
+{
+  for( std::size_t i = 0; i < mQueue.Count() ; ++i )
+  {
+    if( GetCachedTextureId( i ) == textureId )
+    {
+      mQueue[i].mReady = true;
+      break;
+    }
+  }
+}
+
 TextureSet RollingAnimatedImageCache::GetFrontTextureSet() const
 {
   DALI_LOG_INFO( gAnimImgLogFilter, Debug::Concise, "RollingAnimatedImageCache::GetFrontTextureSet() FrameNumber:%d\n", mQueue[ 0 ].mFrameNumber );
@@ -202,6 +230,68 @@ TextureManager::TextureId RollingAnimatedImageCache::GetCachedTextureId( int ind
   return mImageUrls[ mQueue[ index ].mFrameNumber ].mTextureId;
 }
 
+void RollingAnimatedImageCache::CheckFrontFrame( bool wasReady )
+{
+  if( mWaitingForReadyFrame && wasReady == false && IsFrontReady() )
+  {
+    mWaitingForReadyFrame = false;
+    mObserver.FrameReady( GetFrontTextureSet() );
+  }
+}
+
+void RollingAnimatedImageCache::UploadComplete(
+  bool           loadSuccess,
+  int32_t        textureId,
+  TextureSet     textureSet,
+  bool           useAtlasing,
+  const Vector4& atlasRect,
+  bool           preMultiplied )
+{
+  DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::UploadComplete(textureId:%d) start\n", textureId);
+  LOG_CACHE;
+
+  bool frontFrameReady = IsFrontReady();
+
+  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;
+  }
+
+  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.
+  if( !mLoadWaitingQueue.empty() )
+  {
+    uint32_t loadingIndex = mLoadWaitingQueue.front();
+    mLoadWaitingQueue.erase( mLoadWaitingQueue.begin() );
+    mOnLoading = true;
+    RequestFrameLoading( loadingIndex );
+  }
+
+  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 Toolkit
 } //namespace Dali
index 503f65e..8281c32 100644 (file)
@@ -37,7 +37,7 @@ namespace Internal
  * Frames are always ready, so the observer.FrameReady callback is never triggered;
  * the FirstFrame and NextFrame APIs will always return a texture.
  */
-class RollingAnimatedImageCache : public ImageCache
+class RollingAnimatedImageCache : public ImageCache, public TextureUploadObserver
 {
 public:
   /**
@@ -48,16 +48,18 @@ 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] isSynchronousLoading The flag to define whether to load first frame synchronously
    *
    * This will start loading textures immediately, according to the
    * batch and cache sizes.
    */
   RollingAnimatedImageCache( TextureManager&                 textureManager,
-                        AnimatedImageLoading&           animatedImageLoader,
-                        uint32_t                        frameCount,
-                        ImageCache::FrameReadyObserver& observer,
-                        uint16_t                        cacheSize,
-                        uint16_t                        batchSize );
+                             AnimatedImageLoading&           animatedImageLoader,
+                             uint32_t                        frameCount,
+                             ImageCache::FrameReadyObserver& observer,
+                             uint16_t                        cacheSize,
+                             uint16_t                        batchSize,
+                             bool                            isSynchronousLoading );
 
   /**
    * Destructor
@@ -88,11 +90,21 @@ private:
   bool IsFrontReady() const;
 
   /**
+   * Request to Load a frame
+   */
+  void RequestFrameLoading( uint32_t frameIndex );
+
+  /**
    * Load the next batch of images
    */
   void LoadBatch();
 
   /**
+   * Find the matching image frame, and set it to ready
+   */
+  void SetImageFrameReady( TextureManager::TextureId textureId );
+
+  /**
    * Get the texture set of the front frame.
    * @return the texture set
    */
@@ -103,6 +115,27 @@ private:
    */
   TextureManager::TextureId GetCachedTextureId( int index ) const;
 
+  /**
+   * Check if the front frame has become ready - if so, inform observer
+   * @param[in] wasReady Readiness before call.
+   */
+  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;
+
 private:
   /**
    * Secondary class to hold readiness and index into url
@@ -110,14 +143,18 @@ private:
   struct ImageFrame
   {
     unsigned int mFrameNumber = 0u;
+    bool mReady = false;
   };
 
-  Dali::AnimatedImageLoading& mAnimatedImageLoading;
-  uint32_t                   mFrameCount;
-  int                        mFrameIndex;
-  std::vector<UrlStore>      mImageUrls;
-  uint16_t                   mCacheSize;
-  CircularQueue<ImageFrame>  mQueue;
+  Dali::AnimatedImageLoading  mAnimatedImageLoading;
+  uint32_t                    mFrameCount;
+  int                         mFrameIndex;
+  std::vector<UrlStore>       mImageUrls;
+  std::vector<int32_t>        mIntervals;
+  std::vector<uint32_t>       mLoadWaitingQueue;
+  CircularQueue<ImageFrame>   mQueue;
+  bool                        mIsSynchronousLoading;
+  bool                        mOnLoading;
 };
 
 } // namespace Internal
index 9823a92..194b9ba 100644 (file)
@@ -609,13 +609,27 @@ bool ImageVisual::AttemptAtlasing()
 void ImageVisual::InitializeRenderer()
 {
   auto attemptAtlasing = AttemptAtlasing();
-  // texture set has to be created first as we need to know if atlasing succeeded or not
-  // when selecting the shader
 
-  if( mTextureId == TextureManager::INVALID_TEXTURE_ID && ! mTextures ) // Only load the texture once
+  // Load Texture if mTextures is empty.
+  // mTextures is already set, the mTexture can be used to create Renderer.
+  // There are two cases mTextures is empty.
+  // 1. mTextureId == TextureManager::INVALID_TEXTURE_ID
+  //  - Visual is on stage with LoadPolicy::ATTACHED
+  // 2. mTextureId != TextureManager::INVALID_TEXTURE_ID
+  //  - If ReleasePolicy is DESTROYED, InitializeRenderer called every on stage called.
+  //  - Then every resources those contained in Visual are Reset but mTextureId is remained when the Off stage time,
+  //  - So, mTextures needed to be get from texture manager to created resources like mImpl->mRenderer.
+  if( ! mTextures )
   {
-    LoadTexture( attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection,
-                 TextureManager::ReloadPolicy::CACHED );
+    if( mTextureId == TextureManager::INVALID_TEXTURE_ID )
+    {
+      LoadTexture( attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection,
+                   TextureManager::ReloadPolicy::CACHED );
+    }
+    else
+    {
+      mTextures = mFactoryCache.GetTextureManager().GetTextureSet( mTextureId );
+    }
   }
 
   CreateRenderer( mTextures );
index 6ba1a99..147f88c 100644 (file)
@@ -431,6 +431,8 @@ void NPatchVisual::OnSetTransform()
 void NPatchVisual::DoCreatePropertyMap( Property::Map& map ) const
 {
   map.Clear();
+  bool sync = IsSynchronousLoadingRequired();
+  map.Insert( Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, sync );
   map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::N_PATCH );
   map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl() );
   map.Insert( Toolkit::ImageVisual::Property::BORDER_ONLY, mBorderOnly );
index 5c694d0..e23290b 100644 (file)
@@ -143,6 +143,71 @@ 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 textureSet;
+
+  if( synchronousLoading )
+  {
+    Devel::PixelBuffer pixelBuffer;
+    if( animatedImageLoading )
+    {
+      pixelBuffer = animatedImageLoading.LoadFrame( frameIndex );
+    }
+    if( !pixelBuffer )
+    {
+      // use broken image
+      pixelBuffer = LoadImageFromFile( mBrokenImageUrl );
+      PixelData pixelData;
+      if( pixelBuffer )
+      {
+        pixelData = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
+      }
+      Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(),
+                                      pixelData.GetWidth(), pixelData.GetHeight() );
+      texture.Upload( pixelData );
+      textureSet = TextureSet::New();
+      textureSet.SetTexture( 0u, texture );
+    }
+    else
+    {
+      PixelData pixelData = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
+      if( !textureSet )
+      {
+        Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(),
+                                        pixelData.GetWidth(), pixelData.GetHeight() );
+        texture.Upload( pixelData );
+        textureSet = TextureSet::New();
+        textureSet.SetTexture( 0u, texture );
+      }
+    }
+  }
+  else
+  {
+    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, UPLOAD_TO_TEXTURE, textureObserver,
+                                     true, TextureManager::ReloadPolicy::CACHED, preMultiply, animatedImageLoading, frameIndex );
+    TextureManager::LoadState loadState = GetTextureStateInternal( textureId );
+    if( loadState == TextureManager::UPLOADED )
+    {
+      // UploadComplete has already been called - keep the same texture set
+      textureSet = GetTextureSet( textureId );
+    }
+  }
+
+  if( textureSet )
+  {
+    Sampler sampler = Sampler::New();
+    sampler.SetWrapMode(  wrapModeU, wrapModeV  );
+    textureSet.SetSampler( 0u, sampler );
+  }
+
+  return textureSet;
+}
+
 Devel::PixelBuffer TextureManager::LoadPixelBuffer(
   const VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode, bool synchronousLoading, TextureUploadObserver* textureObserver, bool orientationCorrection, TextureManager::MultiplyOnLoad& preMultiplyOnLoad )
 {
@@ -163,7 +228,7 @@ Devel::PixelBuffer TextureManager::LoadPixelBuffer(
   {
     RequestLoadInternal( url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS,
                          false, RETURN_PIXEL_BUFFER, textureObserver, orientationCorrection, TextureManager::ReloadPolicy::FORCED,
-                         preMultiplyOnLoad );
+                         preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u );
   }
 
   return pixelBuffer;
@@ -335,7 +400,7 @@ TextureManager::TextureId TextureManager::RequestLoad(
 {
   return RequestLoadInternal( url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, useAtlas,
                               false, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy,
-                              preMultiplyOnLoad );
+                              preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u );
 }
 
 TextureManager::TextureId TextureManager::RequestLoad(
@@ -354,7 +419,7 @@ TextureManager::TextureId TextureManager::RequestLoad(
 {
   return RequestLoadInternal( url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas,
                               cropToMask, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy,
-                              preMultiplyOnLoad );
+                              preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u );
 }
 
 TextureManager::TextureId TextureManager::RequestMaskLoad( const VisualUrl& maskUrl )
@@ -363,7 +428,7 @@ TextureManager::TextureId TextureManager::RequestMaskLoad( const VisualUrl& 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, KEEP_PIXEL_BUFFER, NULL, true,
-                              TextureManager::ReloadPolicy::CACHED, preMultiply );
+                              TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u );
 }
 
 TextureManager::TextureId TextureManager::RequestLoadInternal(
@@ -379,16 +444,19 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
   TextureUploadObserver*          observer,
   bool                            orientationCorrection,
   TextureManager::ReloadPolicy    reloadPolicy,
-  TextureManager::MultiplyOnLoad& preMultiplyOnLoad )
+  TextureManager::MultiplyOnLoad& preMultiplyOnLoad,
+  Dali::AnimatedImageLoading      animatedImageLoading,
+  uint32_t                        frameIndex )
 {
   // First check if the requested Texture is cached.
+  bool isAnimatedImage = ( animatedImageLoading ) ? true : false;
   const TextureHash textureHash = GenerateHash( url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas,
-                                                maskTextureId );
+                                                maskTextureId, storageType, isAnimatedImage, frameIndex );
 
   TextureManager::TextureId textureId = INVALID_TEXTURE_ID;
   // Look up the texture by hash. Note: The extra parameters are used in case of a hash collision.
   int cacheIndex = FindCachedTexture( textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas,
-                                      maskTextureId, preMultiplyOnLoad, storageType );
+                                      maskTextureId, preMultiplyOnLoad, storageType, isAnimatedImage, frameIndex );
 
   // Check if the requested Texture exists in the cache.
   if( cacheIndex != INVALID_CACHE_INDEX )
@@ -416,7 +484,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
     mTextureInfoContainer.push_back( TextureInfo( textureId, maskTextureId, url.GetUrl(),
                                                   desiredSize, contentScale, fittingMode, samplingMode,
                                                   false, cropToMask, useAtlas, textureHash, orientationCorrection,
-                                                  preMultiply ) );
+                                                  preMultiply, animatedImageLoading, frameIndex ) );
     cacheIndex = mTextureInfoContainer.size() - 1u;
 
     DALI_LOG_INFO( gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n",
@@ -675,7 +743,6 @@ TextureSet TextureManager::RemoveExternalTexture( const std::string& url )
   return TextureSet();
 }
 
-
 void TextureManager::AddObserver( TextureManager::LifecycleObserver& observer )
 {
   // make sure an observer doesn't observe the same object twice
@@ -763,10 +830,17 @@ void TextureManager::LoadTexture( TextureInfo& textureInfo, TextureUploadObserve
     auto premultiplyOnLoad = ( textureInfo.preMultiplyOnLoad && textureInfo.maskTextureId == INVALID_TEXTURE_ID ) ?
                                DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF;
     DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End());
-    loadingHelperIt->Load(textureInfo.textureId, textureInfo.url,
-                          textureInfo.desiredSize, textureInfo.fittingMode,
-                          textureInfo.samplingMode, textureInfo.orientationCorrection,
-                          premultiplyOnLoad );
+    if( textureInfo.animatedImageLoading )
+    {
+      loadingHelperIt->LoadAnimatedImage( textureInfo.textureId, textureInfo.animatedImageLoading, textureInfo.frameIndex );
+    }
+    else
+    {
+      loadingHelperIt->Load(textureInfo.textureId, textureInfo.url,
+                            textureInfo.desiredSize, textureInfo.fittingMode,
+                            textureInfo.samplingMode, textureInfo.orientationCorrection,
+                            premultiplyOnLoad );
+    }
   }
   ObserveTexture( textureInfo, observer );
 }
@@ -1078,7 +1152,10 @@ TextureManager::TextureHash TextureManager::GenerateHash(
   const FittingMode::Type        fittingMode,
   const Dali::SamplingMode::Type samplingMode,
   const UseAtlas                 useAtlas,
-  TextureId                      maskTextureId )
+  TextureId                      maskTextureId,
+  StorageType                    storageType,
+  bool                           isAnimationImage,
+  uint32_t                       frameIndex )
 {
   std::string hashTarget( url );
   const size_t urlLength = hashTarget.length();
@@ -1099,8 +1176,8 @@ TextureManager::TextureHash TextureManager::GenerateHash(
     *hashTargetPtr++ = ( size.GetHeight() >> 8u ) & 0xff;
 
     // Bit-pack the FittingMode, SamplingMode and atlasing.
-    // FittingMode=2bits, SamplingMode=3bits, useAtlas=1bit
-    *hashTargetPtr   = ( fittingMode << 4u ) | ( samplingMode << 1 ) | useAtlas;
+    // FittingMode=2bits, SamplingMode=3bits, useAtlas=1bit, storageType=2bits
+    *hashTargetPtr   = ( fittingMode << 6u ) | ( samplingMode << 3 ) | ( useAtlas << 2 ) | storageType;
   }
   else
   {
@@ -1123,6 +1200,19 @@ TextureManager::TextureHash TextureManager::GenerateHash(
     }
   }
 
+  if( isAnimationImage )
+  {
+    auto textureIdIndex = hashTarget.length();
+    hashTarget.resize( hashTarget.length() + sizeof( uint32_t ) );
+    char* hashTargetPtr = &( hashTarget[ textureIdIndex ] );
+
+    for( size_t byteIter = 0; byteIter < sizeof( uint32_t ); ++byteIter )
+    {
+      *hashTargetPtr++ = frameIndex & 0xff;
+      frameIndex >>= 8u;
+    }
+  }
+
   if( maskTextureId != INVALID_TEXTURE_ID )
   {
     auto textureIdIndex = hashTarget.length();
@@ -1150,7 +1240,9 @@ int TextureManager::FindCachedTexture(
   const bool                        useAtlas,
   TextureId                         maskTextureId,
   TextureManager::MultiplyOnLoad    preMultiplyOnLoad,
-  StorageType                       storageType )
+  StorageType                       storageType,
+  bool                              isAnimatedImage,
+  uint32_t                          frameIndex )
 {
   // Default to an invalid ID, in case we do not find a match.
   int cacheIndex = INVALID_CACHE_INDEX;
@@ -1171,7 +1263,9 @@ int TextureManager::FindCachedTexture(
           ( ( size.GetWidth() == 0 && size.GetHeight() == 0 ) ||
             ( fittingMode == textureInfo.fittingMode &&
               samplingMode == textureInfo.samplingMode ) ) &&
-          ( storageType == textureInfo.storageType ) )
+          ( storageType == textureInfo.storageType ) &&
+          ( isAnimatedImage == ( ( textureInfo.animatedImageLoading ) ? true : false ) ) &&
+          ( frameIndex == textureInfo.frameIndex ) )
       {
         // 1. If preMultiplyOnLoad is MULTIPLY_ON_LOAD, then textureInfo.preMultiplyOnLoad should be true. The premultiplication result can be different.
         // 2. If preMultiplyOnLoad is LOAD_WITHOUT_MULTIPLY, then textureInfo.preMultiplied should be false.
@@ -1217,27 +1311,36 @@ TextureManager::AsyncLoadingHelper::AsyncLoadingHelper(TextureManager& textureMa
 {
 }
 
-void TextureManager::AsyncLoadingHelper::Load(TextureId          textureId,
-                                              const VisualUrl&   url,
-                                              ImageDimensions    desiredSize,
-                                              FittingMode::Type  fittingMode,
-                                              SamplingMode::Type samplingMode,
-                                              bool               orientationCorrection,
-                                              DevelAsyncImageLoader::PreMultiplyOnLoad  preMultiplyOnLoad)
+void TextureManager::AsyncLoadingHelper::LoadAnimatedImage( TextureId                   textureId,
+                                                            Dali::AnimatedImageLoading  animatedImageLoading,
+                                                            uint32_t                    frameIndex )
+{
+  mLoadingInfoContainer.push_back( AsyncLoadingInfo( textureId ) );
+  auto id = DevelAsyncImageLoader::LoadAnimatedImage( mLoader, animatedImageLoading, frameIndex );
+  mLoadingInfoContainer.back().loadId = id;
+}
+
+void TextureManager::AsyncLoadingHelper::Load( TextureId                                textureId,
+                                               const VisualUrl&                         url,
+                                               ImageDimensions                          desiredSize,
+                                               FittingMode::Type                        fittingMode,
+                                               SamplingMode::Type                       samplingMode,
+                                               bool                                     orientationCorrection,
+                                               DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad )
 {
-  mLoadingInfoContainer.push_back(AsyncLoadingInfo(textureId));
+  mLoadingInfoContainer.push_back( AsyncLoadingInfo( textureId ) );
   auto id = DevelAsyncImageLoader::Load( mLoader, url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad );
   mLoadingInfoContainer.back().loadId = id;
 }
 
-void TextureManager::AsyncLoadingHelper::ApplyMask( TextureId textureId,
-                                                    Devel::PixelBuffer pixelBuffer,
-                                                    Devel::PixelBuffer maskPixelBuffer,
-                                                    float contentScale,
-                                                    bool cropToMask,
+void TextureManager::AsyncLoadingHelper::ApplyMask( TextureId                                textureId,
+                                                    Devel::PixelBuffer                       pixelBuffer,
+                                                    Devel::PixelBuffer                       maskPixelBuffer,
+                                                    float                                    contentScale,
+                                                    bool                                     cropToMask,
                                                     DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad )
 {
-  mLoadingInfoContainer.push_back(AsyncLoadingInfo(textureId));
+  mLoadingInfoContainer.push_back( AsyncLoadingInfo( textureId ) );
   auto id = DevelAsyncImageLoader::ApplyMask( mLoader, pixelBuffer, maskPixelBuffer, contentScale, cropToMask, preMultiplyOnLoad );
   mLoadingInfoContainer.back().loadId = id;
 }
index cc5c0e4..c3cd015 100755 (executable)
@@ -164,6 +164,33 @@ public:
   // TextureManager Main API:
 
   /**
+   * @brief Requests an frame of animated image load.
+   *
+   * 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).
+   *
+   * @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,
+                                       TextureManager::TextureId& textureId,
+                                       Dali::WrapMode::Type wrapModeU, Dali::WrapMode::Type wrapModeV,
+                                       TextureUploadObserver* textureObserver );
+
+  /**
    * @brief Requests an image load of the given URL to get PixelBuffer.
    *
    * The parameters are used to specify how the image is loaded.
@@ -431,6 +458,8 @@ private:
    * @param[in] reloadPolicy          Forces a reload of the texture even if already cached
    * @param[in] preMultiplyOnLoad     True if the image color should be multiplied by it's alpha. Set to false if
    *                                  there is no alpha
+   * @param[in] animatedImageLoading  The AnimatedImageLoading to load animated image
+   * @param[in] frameIndex            The frame index of a frame to be loaded frame
    * @return                          A TextureId to use as a handle to reference this Texture
    */
   TextureId RequestLoadInternal(
@@ -446,7 +475,9 @@ private:
     TextureUploadObserver*              observer,
     bool                                orientationCorrection,
     TextureManager::ReloadPolicy        reloadPolicy,
-    MultiplyOnLoad&                     preMultiplyOnLoad );
+    MultiplyOnLoad&                     preMultiplyOnLoad,
+    Dali::AnimatedImageLoading          animatedImageLoading,
+    uint32_t                            frameIndex );
 
   /**
    * @brief Get the current state of a texture
@@ -477,7 +508,9 @@ private:
                  UseAtlas useAtlas,
                  TextureManager::TextureHash hash,
                  bool orientationCorrection,
-                 bool preMultiplyOnLoad )
+                 bool preMultiplyOnLoad,
+                 Dali::AnimatedImageLoading animatedImageLoading,
+                 uint32_t frameIndex )
     : url( url ),
       desiredSize( desiredSize ),
       useSize( desiredSize ),
@@ -491,6 +524,8 @@ private:
       fittingMode( fittingMode ),
       samplingMode( samplingMode ),
       storageType( UPLOAD_TO_TEXTURE ),
+      animatedImageLoading( animatedImageLoading ),
+      frameIndex( frameIndex ),
       loadSynchronously( loadSynchronously ),
       useAtlas( useAtlas ),
       cropToMask( cropToMask ),
@@ -522,6 +557,8 @@ private:
     FittingMode::Type fittingMode:3; ///< The requested FittingMode
     Dali::SamplingMode::Type samplingMode:3; ///< The requested SamplingMode
     StorageType storageType:2;     ///< 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
     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
@@ -685,18 +722,20 @@ private:
    * Only applies size, fitting mode andsampling mode if the size is specified.
    * Only applies maskTextureId if it isn't INVALID_TEXTURE_ID
    * Always applies useAtlas.
-   * @param[in] url          The URL of the image to load
-   * @param[in] size         The image size
-   * @param[in] fittingMode  The FittingMode to use
-   * @param[in] samplingMode The SamplingMode to use
-   * @param[in] useAtlas     True if atlased
-   * @param[in] maskTextureId The masking texture id (or INVALID_TEXTURE_ID)
-   * @return                 A hash of the provided data for caching.
+   * @param[in] url              The URL of the image to load
+   * @param[in] size             The image size
+   * @param[in] fittingMode      The FittingMode to use
+   * @param[in] samplingMode     The SamplingMode to use
+   * @param[in] useAtlas         True if atlased
+   * @param[in] maskTextureId    The masking texture id (or INVALID_TEXTURE_ID)
+   * @param[in] isAnimatedImage  The boolean value to know whether the request is for animated image or not
+   * @param[in] frameIndex       The frame index of a frame to be loaded frame
+   * @return                     A hash of the provided data for caching.
    */
   TextureHash GenerateHash( const std::string& url, const ImageDimensions size,
                             const FittingMode::Type fittingMode,
                             const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas,
-                            TextureId maskTextureId );
+                            TextureId maskTextureId, StorageType storageType, bool isAnimatedImage, uint32_t frameIndex );
 
   /**
    * @brief Looks up a cached texture by its hash.
@@ -710,7 +749,9 @@ private:
    * @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] storageType       Whether the pixel data is stored in the cache, returned with PixelBuffer or uploaded to the GPU
-   * @return A TextureId of a cached Texture if found. Or INVALID_TEXTURE_ID if not found.
+   * @param[in] isAnimatedImage   The boolean value to know whether the request is for animated image or not
+   * @param[in] frameIndex        The frame index of a frame to be loaded frame
+   * @return                      A TextureId of a cached Texture if found. Or INVALID_TEXTURE_ID if not found.
    */
   TextureManager::TextureId FindCachedTexture(
     const TextureManager::TextureHash hash,
@@ -721,7 +762,9 @@ private:
     const bool useAtlas,
     TextureId maskTextureId,
     MultiplyOnLoad preMultiplyOnLoad,
-    StorageType storageType );
+    StorageType storageType,
+    bool isAnimatedImage,
+    uint32_t frameIndex );
 
 private:
 
@@ -738,6 +781,16 @@ private:
     AsyncLoadingHelper(TextureManager& textureManager);
 
     /**
+     * @brief Load a new frame of animated image
+     * @param[in] textureId             TextureId to reference the texture that will be loaded
+     * @param[in] animatedImageLoading  The AnimatedImageLoading to load animated image
+     * @param[in] frameIndex            The frame index of a frame to be loaded frame
+     */
+    void LoadAnimatedImage( TextureId textureId,
+                            Dali::AnimatedImageLoading animatedImageLoading,
+                            uint32_t frameIndex);
+
+    /**
      * @brief Load a new texture.
      * @param[in] textureId             TextureId to reference the texture that will be loaded
      * @param[in] url                   The URL of the image to load
index 6e9fd15..6b99619 100644 (file)
@@ -31,7 +31,7 @@ namespace Toolkit
 
 const unsigned int TOOLKIT_MAJOR_VERSION = 1;
 const unsigned int TOOLKIT_MINOR_VERSION = 9;
-const unsigned int TOOLKIT_MICRO_VERSION = 19;
+const unsigned int TOOLKIT_MICRO_VERSION = 20;
 const char * const TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index 0f5d58b..c28b059 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_IMAGE_VISUAL_PROPERTIES_H
 
 /*
- * 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.
@@ -184,19 +184,21 @@ enum
   /**
    * @brief Defines the batch size for pre-loading images in the AnimatedImageVisual
    * @details Name "batchSize", type Property::INTEGER, number of images to pre-load
-   * before starting to play. Default value: 1
+   * before starting to play. Default value: 2
    * @SINCE_1_2.60
    * @note Optional.
+   * @note Minimum supported value is 2.
    */
   BATCH_SIZE,
 
   /**
    * @brief Defines the cache size for loading images in the AnimatedImageVisual
    * @details Name "cacheSize", type Property::INTEGER, number of images to keep
-   * cached ahead during playback. Default value: 1
+   * cached ahead during playback. Default value: 2
    *
    * @SINCE_1_2.60
    * @note Optional.
+   * @note Minimum supported value is 2.
    * @note, cacheSize should be >= batchSize.
    * If it isn't, then the cache will automatically be changed to batchSize.
    * @note, because of the defaults, it is expected that the application developer
index 3864042..b2f11d8 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali2-toolkit
 Summary:    Dali 3D engine Toolkit
-Version:    1.9.19
+Version:    1.9.20
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT