[4.0] ImageVisual Load policy 43/158543/1
authorAgnelo Vaz <agnelo.vaz@samsung.com>
Wed, 18 Oct 2017 08:12:00 +0000 (09:12 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Wed, 1 Nov 2017 18:08:23 +0000 (18:08 +0000)
ImageVisual can be created with a PropertyMap that inserts a load policy.

Depending on the load policy the image(texture) will load immediately when the visual
is created or when the visual is attached to the stage.

Can be used to preload special images so can be displayed immediately on request.

Registered Visuals with LoadPolicy::IMMEDIATE will signal ResourceReadySignal when attached to stage.

Limitations:

Atlasing not supported with IMMEDIATE mode currently.

Change-Id: I3e1b3fd19f3027edb62858549890972f6a166cd0
Signed-off-by: Adeel Kazmi <adeel.kazmi@samsung.com>
automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp
dali-toolkit/devel-api/visuals/image-visual-properties-devel.h
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/image/image-visual.h
dali-toolkit/internal/visuals/texture-manager-impl.cpp
dali-toolkit/internal/visuals/visual-string-constants.cpp
dali-toolkit/internal/visuals/visual-string-constants.h

index d0e1561..1bd6203 100644 (file)
@@ -49,6 +49,13 @@ const char* TEST_REMOTE_IMAGE_FILE_NAME = "https://www.tizen.org/sites/all/theme
 const char* TEST_INVALID_FILE_NAME =  TEST_RESOURCE_DIR  "/invalid.jpg";
 const char* TEST_REMOTE_INVALID_FILE_NAME = "https://www.tizen.org/invalid.png";
 const char* TEST_MASK_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR "/mask.png";
+
+
+bool gResourceReadySignalFired = false;
+
+void ResourceReadySignal( Control control )
+{
+  gResourceReadySignalFired = true;
 }
 
 
@@ -65,6 +72,23 @@ Actor CreateActorWithImageVisual(const Property::Map& map)
   return actor;
 }
 
+
+Visual::Base CreateVisualWithPolicy( const char* url, Property::Index key, const Property::Value& value )
+{
+  VisualFactory factory = VisualFactory::Get();
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  url );
+  propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH,   20 );
+  propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT,   30 );
+  propertyMap.Insert( key , value );
+
+  return factory.CreateVisual( propertyMap );
+}
+
+} // namespace
+
 void TestVisualRender( ToolkitTestApplication& application,
                        DummyControl& actor,
                        Visual::Base& visual,
@@ -223,6 +247,7 @@ int UtcDaliImageVisualTextureReuse1(void)
   Property::Map propertyMap;
   propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
   propertyMap.Insert( ImageVisual::Property::URL, TEST_LARGE_IMAGE_FILE_NAME );
+  propertyMap.Insert( DevelImageVisual::Property::RELEASE_POLICY,  DevelImageVisual::ReleasePolicy::DETACHED );
 
   TestGlAbstraction& gl = application.GetGlAbstraction();
   TraceCallStack& textureTrace = gl.GetTextureTrace();
@@ -274,7 +299,7 @@ int UtcDaliImageVisualTextureReuse1(void)
 
   tet_infoline("Test that removing last actor does delete the texture\n");
 
-  Stage::GetCurrent().Remove( actor2 );
+  Stage::GetCurrent().Remove( actor2 ); // Detaches remaining ImageVisual
   application.SendNotification();
   application.Render();
 
@@ -1188,16 +1213,7 @@ int UtcDaliImageVisualReleasePolicy01(void)
   ToolkitTestApplication application;
   tet_infoline( "UtcDaliImageVisualReleasePolicy01 Detached Policy, disabling visual with this policy deletes texture" );
 
-  VisualFactory factory = VisualFactory::Get();
-
-  Property::Map propertyMap;
-  propertyMap.Insert( Visual::Property::TYPE,  Visual::IMAGE );
-  propertyMap.Insert( ImageVisual::Property::URL,  TEST_IMAGE_FILE_NAME );
-  propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH,   20 );
-  propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT,   30 );
-  propertyMap.Insert( DevelImageVisual::Property::RELEASE_POLICY, DevelImageVisual::ReleasePolicy::DETACHED );
-
-  Visual::Base imageVisual = factory.CreateVisual(propertyMap);
+  Visual::Base imageVisual = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, DevelImageVisual::Property::RELEASE_POLICY, DevelImageVisual::ReleasePolicy::DETACHED );
   DALI_TEST_CHECK( imageVisual );
 
   // Set up debug trace
@@ -1247,18 +1263,7 @@ int UtcDaliImageVisualReleasePolicy02(void)
   ToolkitTestApplication application;
   tet_infoline( "UtcDaliImageVisualReleasePolicy02 Destroyed Policy, Texture should be deleted when visual destroyed" );
 
-  VisualFactory factory = VisualFactory::Get();
-  const std::string MASK_IMAGE = TEST_REMOTE_IMAGE_FILE_NAME;
-
-  Property::Map propertyMap;
-  propertyMap.Insert( Visual::Property::TYPE,  Visual::IMAGE );
-  propertyMap.Insert( Visual::Property::MIX_COLOR, Color::MAGENTA );
-  propertyMap.Insert( ImageVisual::Property::URL,  TEST_IMAGE_FILE_NAME );
-  propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH,   20 );
-  propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT,   30 );
-  propertyMap.Insert( DevelImageVisual::Property::RELEASE_POLICY , DevelImageVisual::ReleasePolicy::DESTROYED );
-
-  Visual::Base imageVisual = factory.CreateVisual(propertyMap);
+  Visual::Base imageVisual = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, DevelImageVisual::Property::RELEASE_POLICY, DevelImageVisual::ReleasePolicy::DESTROYED );
   DALI_TEST_CHECK( imageVisual );
 
   // Setup debug trace
@@ -1310,16 +1315,7 @@ int UtcDaliImageVisualReleasePolicy03(void)
   ToolkitTestApplication application;
   tet_infoline( "UtcDaliImageVisualReleasePolicy03 Never Policy, texture should not be deleted after visual destroyed" );
 
-  VisualFactory factory = VisualFactory::Get();
-
-  Property::Map propertyMap;
-  propertyMap.Insert( Visual::Property::TYPE,  Visual::IMAGE );
-  propertyMap.Insert( ImageVisual::Property::URL,  TEST_IMAGE_FILE_NAME );
-  propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH,   20 );
-  propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT,   30 );
-  propertyMap.Insert( DevelImageVisual::Property::RELEASE_POLICY , DevelImageVisual::ReleasePolicy::NEVER );
-
-  Visual::Base imageVisual = factory.CreateVisual(propertyMap);
+  Visual::Base imageVisual = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, DevelImageVisual::Property::RELEASE_POLICY, DevelImageVisual::ReleasePolicy::NEVER );
   DALI_TEST_CHECK( imageVisual );
 
   TestGlAbstraction& gl = application.GetGlAbstraction();
@@ -1368,25 +1364,11 @@ int UtcDaliImageVisualReleasePolicy04(void)
   ToolkitTestApplication application;
   tet_infoline( "UtcDaliImageVisualReleasePolicy04 Two visuals with different policies sharing a texture" );
 
-  VisualFactory factory = VisualFactory::Get();
-
   tet_infoline( "Create first visual with Never release policy" );
-  Property::Map propertyMapNeverReleasePolicy;
-  propertyMapNeverReleasePolicy.Insert( Visual::Property::TYPE,  Visual::IMAGE );
-  propertyMapNeverReleasePolicy.Insert( ImageVisual::Property::URL,  TEST_IMAGE_FILE_NAME );
-  propertyMapNeverReleasePolicy.Insert( ImageVisual::Property::DESIRED_WIDTH,   20 );
-  propertyMapNeverReleasePolicy.Insert( ImageVisual::Property::DESIRED_HEIGHT,   30 );
-  propertyMapNeverReleasePolicy.Insert( DevelImageVisual::Property::RELEASE_POLICY , DevelImageVisual::ReleasePolicy::NEVER );
-  Visual::Base imageVisualNever = factory.CreateVisual( propertyMapNeverReleasePolicy );
+  Visual::Base imageVisualNever = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, DevelImageVisual::Property::RELEASE_POLICY, DevelImageVisual::ReleasePolicy::NEVER );
 
   tet_infoline( "Create second visual with Destroyed release policy");
-  Property::Map propertyMapDestroyedReleasePolicy;
-  propertyMapDestroyedReleasePolicy.Insert( Visual::Property::TYPE,  Visual::IMAGE );
-  propertyMapDestroyedReleasePolicy.Insert( ImageVisual::Property::URL,  TEST_IMAGE_FILE_NAME );
-  propertyMapDestroyedReleasePolicy.Insert( ImageVisual::Property::DESIRED_WIDTH,   20 );
-  propertyMapDestroyedReleasePolicy.Insert( ImageVisual::Property::DESIRED_HEIGHT,   30 );
-  propertyMapDestroyedReleasePolicy.Insert( DevelImageVisual::Property::RELEASE_POLICY , DevelImageVisual::ReleasePolicy::DESTROYED );
-  Visual::Base imageVisualDestroyed = factory.CreateVisual( propertyMapDestroyedReleasePolicy );
+    Visual::Base imageVisualDestroyed = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, DevelImageVisual::Property::RELEASE_POLICY, DevelImageVisual::ReleasePolicy::DESTROYED );
 
   // Set up trace debug
   TestGlAbstraction& gl = application.GetGlAbstraction();
@@ -1472,16 +1454,7 @@ int UtcDaliImageVisualReleasePolicy06(void)
   ToolkitTestApplication application;
   tet_infoline( "UtcDaliImageVisualReleasePolicy06 Never Policy, texture should not be affected by Disabling and Enabling visual" );
 
-  VisualFactory factory = VisualFactory::Get();
-
-  Property::Map propertyMap;
-  propertyMap.Insert( Visual::Property::TYPE,  Visual::IMAGE );
-  propertyMap.Insert( ImageVisual::Property::URL,  TEST_IMAGE_FILE_NAME );
-  propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH,   20 );
-  propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT,   30 );
-  propertyMap.Insert( DevelImageVisual::Property::RELEASE_POLICY , DevelImageVisual::ReleasePolicy::NEVER );
-
-  Visual::Base imageVisual = factory.CreateVisual(propertyMap);
+  Visual::Base imageVisual= CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, DevelImageVisual::Property::RELEASE_POLICY, DevelImageVisual::ReleasePolicy::NEVER );
   DALI_TEST_CHECK( imageVisual );
 
   TestGlAbstraction& gl = application.GetGlAbstraction();
@@ -1540,25 +1513,12 @@ int UtcDaliImageVisualReleasePolicy07(void)
   ToolkitTestApplication application;
   tet_infoline( "UtcDaliImageVisualReleasePolicy07 Two visuals with different policies sharing a texture DETACHED and DESTROYED" );
 
-  VisualFactory factory = VisualFactory::Get();
-
   tet_infoline( "Create first visual with DESTROYED release policy" );
-  Property::Map propertyMapNeverReleasePolicy;
-  propertyMapNeverReleasePolicy.Insert( Visual::Property::TYPE,  Visual::IMAGE );
-  propertyMapNeverReleasePolicy.Insert( ImageVisual::Property::URL,  TEST_IMAGE_FILE_NAME );
-  propertyMapNeverReleasePolicy.Insert( ImageVisual::Property::DESIRED_WIDTH,   20 );
-  propertyMapNeverReleasePolicy.Insert( ImageVisual::Property::DESIRED_HEIGHT,   30 );
-  propertyMapNeverReleasePolicy.Insert( DevelImageVisual::Property::RELEASE_POLICY , DevelImageVisual::ReleasePolicy::DESTROYED );
-  Visual::Base imageVisualDestroyed = factory.CreateVisual( propertyMapNeverReleasePolicy );
+  Visual::Base imageVisualDestroyed = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, DevelImageVisual::Property::RELEASE_POLICY, DevelImageVisual::ReleasePolicy::DESTROYED );
+
 
   tet_infoline( "Create second visual with DETACHED release policy");
-  Property::Map propertyMapDestroyedReleasePolicy;
-  propertyMapDestroyedReleasePolicy.Insert( Visual::Property::TYPE,  Visual::IMAGE );
-  propertyMapDestroyedReleasePolicy.Insert( ImageVisual::Property::URL,  TEST_IMAGE_FILE_NAME );
-  propertyMapDestroyedReleasePolicy.Insert( ImageVisual::Property::DESIRED_WIDTH,   20 );
-  propertyMapDestroyedReleasePolicy.Insert( ImageVisual::Property::DESIRED_HEIGHT,   30 );
-  propertyMapDestroyedReleasePolicy.Insert( DevelImageVisual::Property::RELEASE_POLICY , DevelImageVisual::ReleasePolicy::DETACHED );
-  Visual::Base imageVisualDetached = factory.CreateVisual( propertyMapDestroyedReleasePolicy );
+  Visual::Base imageVisualDetached = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, DevelImageVisual::Property::RELEASE_POLICY, DevelImageVisual::ReleasePolicy::DETACHED );
 
   // Set up trace debug
   TestGlAbstraction& gl = application.GetGlAbstraction();
@@ -1612,3 +1572,151 @@ int UtcDaliImageVisualReleasePolicy07(void)
 
   END_TEST;
 }
+
+int UtcDaliImageVisualLoadPolicy01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualLoadPolicy01 Load a visual image before attaching to stage" );
+
+  // Set up trace debug
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  tet_infoline( "Create visual with IMMEDIATE load policy" );
+  Visual::Base imageVisual = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, DevelImageVisual::Property::LOAD_POLICY, DevelImageVisual::LoadPolicy::IMMEDIATE );
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  // Ensure texture has been uploaded
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure texture loading starts after visual created" );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
+
+  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, imageVisual );
+  imageVisual.Reset(); // reduce ref count so only the control keeps the visual alive.
+
+  actor.SetSize(200.f, 200.f);
+  Stage::GetCurrent().Add( actor );
+  tet_infoline( "Ensure nothing triggers another load as texure already loaded" );
+  const unsigned int TIME_OUT_3_SECONDS = 3;
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1, TIME_OUT_3_SECONDS ), false, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+
+  // Ensure texture is deleted when no longer needed (ref count was correct )
+  dummyImpl.UnregisterVisual( DummyControl::Property::TEST_VISUAL );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualLoadPolicy02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualLoadPolicy01 Load a visual image only after attached to stage" );
+
+  // Set up trace debug
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  tet_infoline( "Create visual with IMMEDIATE load policy" );
+  Visual::Base imageVisual = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, DevelImageVisual::Property::LOAD_POLICY, DevelImageVisual::LoadPolicy::ATTACHED );
+
+  const unsigned int TIME_OUT_3_SECONDS = 3;
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1, TIME_OUT_3_SECONDS ), false, TEST_LOCATION );
+
+  // Act on meeage queue even although nothing expected to load
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure texture is not generated yet" );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+  textureTrace.Reset();
+
+  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, imageVisual );
+  imageVisual.Reset(); // reduce ref count so only the control keeps the visual alive.
+
+  actor.SetSize(200.f, 200.f);
+  Stage::GetCurrent().Add( actor );
+  tet_infoline( "Allow image time to load" );
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure texture generated and renderer created" );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+
+  // Ensure texture is delete when no longer needed
+  dummyImpl.UnregisterVisual( DummyControl::Property::TEST_VISUAL );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualLoadPolicy03(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualLoadPolicy03 Load a visual image before attaching to stage and receive ResourceReady signal" );
+
+  // Set up trace debug
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  tet_infoline( "Create visual with IMMEDIATE load policy" );
+  Visual::Base imageVisual = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, DevelImageVisual::Property::LOAD_POLICY, DevelImageVisual::LoadPolicy::IMMEDIATE );
+
+  // Wait for image to load, ResourceReady signal will not be emitted until Visual is registered with a control and on stage.
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  // Ensure texture has been uploaded
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure texture loading starts after visual created" );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
+
+  tet_infoline( "Register visuals with control and ensure it has the only handles" );
+  DummyControl actor = DummyControl::New(true);
+  actor.ResourceReadySignal().Connect( &ResourceReadySignal);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+
+  tet_infoline( "Registering visual attaches it to stage and trigger the loading signal if Image loaded" );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual );
+  imageVisual.Reset(); // reduce ref count so only the control keeps the visual alive.
+  actor.SetSize(200.f, 200.f);
+  // Adding the Control hence Visual to stage will cause the Visual to trigger ResourceReadySignal if the image is already loaded.
+  Stage::GetCurrent().Add( actor ); // If LoadPolicy was not IMMEDIATE then as this point (after attached to stage) the test would need to wait for Loading
+
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+
+  END_TEST;
+}
index d0c9379..e37d712 100644 (file)
@@ -30,6 +30,22 @@ namespace Toolkit
 namespace DevelImageVisual
 {
 
+/**
+ * @brief The policy determining if the image is loaded when the visual is staged or created.
+ */
+namespace LoadPolicy
+{
+
+/**
+ * @brief The available named elements that define the LoadPolicy.
+ */
+enum Type
+{
+  IMMEDIATE = 0,  ///< The image is loaded when the ImageVisual is created.
+  ATTACHED        ///< The image is loaded when the ImageVisual is attached to the stage.
+};
+
+} // namespace LoadPolicy
 
 /**
  * @brief The policy determining when a image is deleted from the cache in relation to the ImageVisual lifetime.
@@ -75,6 +91,14 @@ enum Type
   CROP_TO_MASK        = Dali::Toolkit::ImageVisual::Property::CROP_TO_MASK,
 
   /**
+   * @brief The policy to determine when an image should be loaded.
+   * @details Name "loadPolicy",  Type LoadPolicy::Type (Property::INTEGER)or Property::STRING.
+   * @note Default LoadPolicy::ATTACHED
+   * @see LoadPolicy::Type
+   */
+  LOAD_POLICY = CROP_TO_MASK + 1,
+
+  /**
    * @brief The policy to determine when an image should no longer be cached.
    * @details Name "releasePolicy", Type ReleasePolicy::Type (Property::INTEGER) or Property::STRING
    * @note Default ReleasePolicy::DESTROYED
index 82f7fd1..9522618 100644 (file)
@@ -91,6 +91,12 @@ DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, REPEAT )
 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, MIRRORED_REPEAT )
 DALI_ENUM_TO_STRING_TABLE_END( WRAP_MODE )
 
+// load policies
+DALI_ENUM_TO_STRING_TABLE_BEGIN( LOAD_POLICY )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DevelImageVisual::LoadPolicy, IMMEDIATE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DevelImageVisual::LoadPolicy, ATTACHED )
+DALI_ENUM_TO_STRING_TABLE_END( LOAD_POLICY )
+
 // release policies
 DALI_ENUM_TO_STRING_TABLE_BEGIN( RELEASE_POLICY )
 DALI_ENUM_TO_STRING_WITH_SCOPE( DevelImageVisual::ReleasePolicy, DETACHED )
@@ -274,6 +280,7 @@ ImageVisual::ImageVisual( VisualFactoryCache& factoryCache,
   mSamplingMode( samplingMode ),
   mWrapModeU( WrapMode::DEFAULT ),
   mWrapModeV( WrapMode::DEFAULT ),
+  mLoadPolicy( DevelImageVisual::LoadPolicy::ATTACHED ),
   mReleasePolicy( DevelImageVisual::ReleasePolicy::DETACHED ),
   mAttemptAtlasing( false ),
   mLoading( false )
@@ -293,6 +300,7 @@ ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, const Image& image )
   mSamplingMode( SamplingMode::DEFAULT ),
   mWrapModeU( WrapMode::DEFAULT ),
   mWrapModeV( WrapMode::DEFAULT ),
+  mLoadPolicy( DevelImageVisual::LoadPolicy::ATTACHED ),
   mReleasePolicy( DevelImageVisual::ReleasePolicy::DESTROYED ),
   mAttemptAtlasing( false ),
   mLoading( false )
@@ -383,12 +391,23 @@ void ImageVisual::DoSetProperties( const Property::Map& propertyMap )
       {
         DoSetProperty( Toolkit::ImageVisual::Property::CROP_TO_MASK, keyValue.second );
       }
+      else if ( keyValue.first == LOAD_POLICY_NAME )
+      {
+        DoSetProperty( Toolkit::DevelImageVisual::Property::LOAD_POLICY, keyValue.second );
+      }
       else if( keyValue.first == RELEASE_POLICY_NAME )
       {
         DoSetProperty( Toolkit::DevelImageVisual::Property::RELEASE_POLICY, keyValue.second );
       }
     }
   }
+
+  // Load image immediately if LOAD_POLICY requires it
+  if ( mLoadPolicy == DevelImageVisual::LoadPolicy::IMMEDIATE )
+  {
+    auto attemptAtlasing = mAttemptAtlasing;
+    LoadTexture( attemptAtlasing, mAtlasRect, mTextures );
+  }
 }
 
 void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& value )
@@ -532,6 +551,13 @@ void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& v
       mReleasePolicy = DevelImageVisual::ReleasePolicy::Type( releasePolicy );
       break;
     }
+
+    case Toolkit::DevelImageVisual::Property::LOAD_POLICY:
+    {
+      int loadPolicy;
+      Scripting::GetEnumerationProperty( value, LOAD_POLICY_TABLE, LOAD_POLICY_TABLE_COUNT, loadPolicy );
+      mLoadPolicy = DevelImageVisual::LoadPolicy::Type( loadPolicy );
+    }
   }
 }
 
@@ -714,61 +740,62 @@ bool ImageVisual::IsSynchronousResourceLoading() const
   return mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
 }
 
-/*
-( VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode,
-                                        ImageVisual::MaskingData* maskInfo, bool synchronousLoading,
-                                        TextureManager::TextureId textureId, Vector4& textureRect, bool& atlasingStatus, bool& loadingStatus
- */
-void ImageVisual::InitializeRenderer()
+void ImageVisual::LoadTexture( bool& atlasing, Vector4& atlasRect, TextureSet& textures )
 {
-  mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
-
   TextureManager& textureManager = mFactoryCache.GetTextureManager();
 
-  if( ! mImpl->mCustomShader && mImageUrl.GetProtocolType() == VisualUrl::LOCAL )
+  ImageAtlasManagerPtr atlasManager = nullptr;
+  AtlasUploadObserver* atlasUploadObserver = nullptr;
+  auto textureObserver = this;
+
+  if( atlasing )
   {
-    bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
+    atlasManager = mFactoryCache.GetAtlasManager();
+    atlasUploadObserver = this;
+  }
 
-    Vector4 atlasRect;
+  textures = textureManager.LoadTexture( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode,
+                                         mMaskingData, IsSynchronousResourceLoading(), mTextureId,
+                                         atlasRect, atlasing, mLoading, mWrapModeU,
+                                         mWrapModeV, textureObserver, atlasUploadObserver, atlasManager );
+}
 
-    auto attemptAtlasing = mAttemptAtlasing;
+void ImageVisual::InitializeRenderer()
+{
+  auto attemptAtlasing = ( ! mImpl->mCustomShader && mImageUrl.GetProtocolType() == VisualUrl::LOCAL && mAttemptAtlasing );
 
-    // texture set has to be created first as we need to know if atlasing succeeded or not
-    // when selecting the shader
-    TextureSet textures =
-        textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode,
-                                   mMaskingData, IsSynchronousResourceLoading(), mTextureId,
-                                   atlasRect, attemptAtlasing, mLoading, mWrapModeU,
-                                   mWrapModeV, this, this, mFactoryCache.GetAtlasManager());
-    if(attemptAtlasing)
-    {
-      mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
-    }
-    CreateRenderer( textures );
+  // texture set has to be created first as we need to know if atlasing succeeded or not
+  // when selecting the shader
 
-    if( mImpl->mFlags & Impl::IS_ATLASING_APPLIED ) // the texture is packed inside atlas
-    {
-      mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, atlasRect );
-      if( !defaultWrapMode ) // custom wrap mode
-      {
-        Vector2 wrapMode(mWrapModeU-WrapMode::CLAMP_TO_EDGE, mWrapModeV-WrapMode::CLAMP_TO_EDGE);
-        wrapMode.Clamp( Vector2::ZERO, Vector2( 2.f, 2.f ) );
-        mImpl->mRenderer.RegisterProperty( WRAP_MODE_UNIFORM_NAME, wrapMode );
-      }
-    }
+  if( mTextureId == TextureManager::INVALID_TEXTURE_ID && ! mTextures ) // Only load the texture once
+  {
+    LoadTexture( attemptAtlasing, mAtlasRect, mTextures );
+  }
+
+  if( attemptAtlasing ) // Flag needs to be set before creating renderer
+  {
+    mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
   }
   else
   {
-    auto attemptAtlasing = false;
-    // for custom shader or remote image, atlas is not applied
-    Vector4 atlasRect; // ignored in this case
-    TextureSet textures =
-        textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode,
-                                   mMaskingData, IsSynchronousResourceLoading(), mTextureId,
-                                   atlasRect, attemptAtlasing, mLoading, mWrapModeU, mWrapModeV, this,
-                                   nullptr, nullptr); // no atlasing
-    DALI_ASSERT_DEBUG(attemptAtlasing == false);
-    CreateRenderer( textures );
+    mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
+  }
+
+  CreateRenderer( mTextures );
+  mTextures.Reset(); // Visual should not keep a handle to the texture after this point.
+
+  if( attemptAtlasing ) // the texture is packed inside atlas
+  {
+    mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mAtlasRect );
+
+    bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
+
+    if( !defaultWrapMode ) // custom wrap mode
+    {
+      Vector2 wrapMode(mWrapModeU-WrapMode::CLAMP_TO_EDGE, mWrapModeV-WrapMode::CLAMP_TO_EDGE);
+      wrapMode.Clamp( Vector2::ZERO, Vector2( 2.f, 2.f ) );
+      mImpl->mRenderer.RegisterProperty( WRAP_MODE_UNIFORM_NAME, wrapMode );
+    }
   }
 }
 
@@ -786,7 +813,7 @@ void ImageVisual::InitializeRenderer( const Image& image )
   else
   {
     // reuse existing code for regular images
-    CreateRenderer( textures );
+    CreateRenderer( textures ); // Textures will be retreived from Image
   }
   ApplyImageToSampler( image );
 }
@@ -892,6 +919,7 @@ void ImageVisual::DoCreatePropertyMap( Property::Map& map ) const
     map.Insert( Toolkit::ImageVisual::Property::CROP_TO_MASK, mMaskingData->mCropToMask );
   }
 
+  map.Insert( Toolkit::DevelImageVisual::Property::LOAD_POLICY, mLoadPolicy );
   map.Insert( Toolkit::DevelImageVisual::Property::RELEASE_POLICY, mReleasePolicy );
 
 }
@@ -981,8 +1009,8 @@ void ImageVisual::UploadCompleted()
   Actor actor = mPlacementActor.GetHandle();
   if( actor )
   {
+    mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mAtlasRect );
     actor.AddRenderer( mImpl->mRenderer );
-
     // reset the weak handle so that the renderer only get added to actor once
     mPlacementActor.Reset();
   }
@@ -997,10 +1025,14 @@ void ImageVisual::UploadComplete( bool loadingSuccess, int32_t textureId, Textur
   {
     if( mImpl->mRenderer )
     {
+      if( usingAtlas )
+      {
+        mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mAtlasRect );
+      }
+
       actor.AddRenderer( mImpl->mRenderer );
       // reset the weak handle so that the renderer only get added to actor once
       mPlacementActor.Reset();
-
       if( loadingSuccess )
       {
         Sampler sampler = Sampler::New();
index 0e4009b..87111b7 100644 (file)
@@ -65,6 +65,7 @@ typedef IntrusivePtr< ImageVisual > ImageVisualPtr;
  * | pixelArea          | VECTOR4           |
  * | wrapModeU          | INTEGER OR STRING |
  * | wrapModeV          | INTEGER OR STRING |
+ * | loadPolicy         | INTEGER OR STRING |
  * | releasePolicy      | INTEGER OR STRING |
  *
  * where pixelArea is a rectangular area.
@@ -96,6 +97,9 @@ typedef IntrusivePtr< ImageVisual > ImageVisualPtr;
  *   "DONT_CARE"
  *   "DEFAULT"
  *
+ * where loadPolicy should be one of the following image loading modes
+ *   "IMMEDIATE"   // Loads image even if visual not attached to stage yet
+ *   "ATTACHED"    // Only loads image once visual is attached to stage
  *
  * where releasePolicy should be one of the following policies for when to cache the image
  *   "DETACHED"    //  Release image from cache when visual detached from stage
@@ -265,6 +269,14 @@ private:
   void ApplyImageToSampler( const Image& image );
 
   /**
+   * @brief Load the texture, will try to atlas unless unable or param set to false.
+   * @param[in, out] atlasing flag if the image has been put in a atlas (true), passing false will not atlas even if possible.
+   * @param[out] atlasRect if atlasing is used this the texture area of the image in the atlas.
+   * @param[out] textures resulting texture set from the image loading.
+   */
+  void LoadTexture( bool& atlasing, Vector4& atlasRect, TextureSet& textures );
+
+  /**
    * @brief Initializes the Dali::Renderer from the image url
    */
   void InitializeRenderer();
@@ -332,12 +344,15 @@ private:
 
   Dali::ImageDimensions mDesiredSize;
   TextureManager::TextureId mTextureId;
+  TextureSet mTextures;
 
   Dali::FittingMode::Type mFittingMode:3;
   Dali::SamplingMode::Type mSamplingMode:4;
   Dali::WrapMode::Type mWrapModeU:3;
   Dali::WrapMode::Type mWrapModeV:3;
+  DevelImageVisual::LoadPolicy::Type mLoadPolicy;
   DevelImageVisual::ReleasePolicy::Type mReleasePolicy;
+  Vector4 mAtlasRect;
   bool mAttemptAtlasing; ///< If true will attempt atlasing, otherwise create unique texture
   bool mLoading;  ///< True if the texture is still loading.
 };
index 66f6a81..e795863 100644 (file)
@@ -135,7 +135,6 @@ TextureSet TextureManager::LoadTexture(
     PixelData data;
     if( url.IsValid() )
     {
-      // if sync loading is required, the loading should immediately when actor is on stage
       Devel::PixelBuffer pixelBuffer = LoadImageFromFile( url.GetUrl(), desiredSize, fittingMode, samplingMode );
       if( pixelBuffer )
       {
index 0670dd8..6282559 100644 (file)
@@ -85,6 +85,7 @@ const char * const CACHE_SIZE_NAME("cacheSize");
 const char * const FRAME_DELAY_NAME("frameDelay");
 const char * const MASK_CONTENT_SCALE_NAME("maskContentScale");
 const char * const CROP_TO_MASK_NAME("cropToMask");
+const char * const LOAD_POLICY_NAME("loadPolicy");
 const char * const RELEASE_POLICY_NAME("releasePolicy");
 
 // Text visual
index 9aa14a1..27030df 100644 (file)
@@ -73,6 +73,7 @@ extern const char * const CACHE_SIZE_NAME;
 extern const char * const FRAME_DELAY_NAME;
 extern const char * const MASK_CONTENT_SCALE_NAME;
 extern const char * const CROP_TO_MASK_NAME;
+extern const char * const LOAD_POLICY_NAME;
 extern const char * const RELEASE_POLICY_NAME;
 
 // Text visual