ImageRenderer provides property to indicate async/sync resource loading 33/70533/7
authorXiangyin Ma <x1.ma@samsung.com>
Thu, 12 May 2016 15:37:02 +0000 (16:37 +0100)
committerXiangyin Ma <x1.ma@samsung.com>
Thu, 26 May 2016 12:47:41 +0000 (05:47 -0700)
Change-Id: I282c0c9d5f904a6d7358b9997357664fbae90e97

13 files changed:
automated-tests/resources/test-image-600.jpg [new file with mode: 0644]
automated-tests/src/dali-toolkit/CMakeLists.txt
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-bitmap-loader.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-bitmap-loader.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ControlRenderer.cpp
automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp
dali-toolkit/internal/controls/image-view/image-view-impl.cpp
dali-toolkit/internal/controls/image-view/image-view-impl.h
dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h
dali-toolkit/internal/controls/renderers/control-renderer-impl.cpp
dali-toolkit/internal/controls/renderers/image/image-renderer.cpp
dali-toolkit/internal/controls/renderers/image/image-renderer.h
dali-toolkit/public-api/controls/image-view/image-view.h

diff --git a/automated-tests/resources/test-image-600.jpg b/automated-tests/resources/test-image-600.jpg
new file mode 100644 (file)
index 0000000..c93db33
Binary files /dev/null and b/automated-tests/resources/test-image-600.jpg differ
index 4d63fee..8a6003f 100644 (file)
@@ -58,6 +58,7 @@ SET(TC_SOURCES
 LIST(APPEND TC_SOURCES
    dali-toolkit-test-utils/toolkit-accessibility-adaptor.cpp
    dali-toolkit-test-utils/toolkit-application.cpp
+   dali-toolkit-test-utils/toolkit-bitmap-loader.cpp
    dali-toolkit-test-utils/toolkit-clipboard.cpp
    dali-toolkit-test-utils/toolkit-clipboard-event-notifier.cpp
    dali-toolkit-test-utils/toolkit-event-thread-callback.cpp
index 00c1204..3acafbd 100644 (file)
  * limitations under the License.
  */
 
+// CLASS HEADER
+#include "toolkit-bitmap-loader.h"
+
+// EXTERNAL INCLUDES
 #include <dali/public-api/object/base-object.h>
-#include <dali/devel-api/adaptor-framework/bitmap-loader.h>
 #include <cstring>
+#include <semaphore.h>
 
 using namespace Dali;
 
 namespace Dali
 {
-class Adaptor;
+namespace
+{
+Dali::BitmapLoader gBitmapLoader;
+}
+
 
 namespace Internal
 {
@@ -49,6 +57,7 @@ public:
     mPixelData(),
     mUrl(url)
   {
+    sem_init( &mySemaphore, 0, 0 );
   }
 
   ~BitmapLoader(){}
@@ -60,6 +69,8 @@ public:
     memset(buffer, 0, bufferSize);
 
     mPixelData = PixelData::New( buffer, mSize.GetWidth(), mSize.GetHeight(), Pixel::RGBA8888, PixelData::FREE);
+
+    sem_post( &mySemaphore );
   }
 
   PixelDataPtr GetPixelData() const
@@ -77,9 +88,19 @@ public:
     return mPixelData ? true : false;
   }
 
+  void WaitForLoading()
+  {
+    if( mPixelData )
+    {
+      return;
+    }
+    sem_wait( &mySemaphore );
+  }
+
   ImageDimensions mSize;
   PixelDataPtr mPixelData;
   const std::string mUrl;
+  sem_t mySemaphore;
 };
 
 } // internal
@@ -101,7 +122,12 @@ inline const Internal::BitmapLoader& GetImplementation(const Dali::BitmapLoader&
 Dali::BitmapLoader Dali::BitmapLoader::New(std::string const&url, Dali::Uint16Pair size, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode, bool orientationCorrection)
 {
   IntrusivePtr<Internal::BitmapLoader> internal = Internal::BitmapLoader::New(url, size, fittingMode, samplingMode, orientationCorrection);
-  return BitmapLoader( internal.Get() );
+  gBitmapLoader = BitmapLoader(internal.Get());
+  return gBitmapLoader;
+}
+
+BitmapLoader::BitmapLoader()
+{
 }
 
 Dali::BitmapLoader::BitmapLoader(Dali::BitmapLoader const& handle)
@@ -115,6 +141,11 @@ Dali::BitmapLoader::BitmapLoader(Internal::BitmapLoader* internal)
 Dali::BitmapLoader::~BitmapLoader()
 {
 }
+BitmapLoader& BitmapLoader::operator=(const BitmapLoader& rhs)
+{
+  BaseHandle::operator=(rhs);
+  return *this;
+}
 void Dali::BitmapLoader::Load()
 {
   GetImplementation(*this).Load();
@@ -131,5 +162,19 @@ bool Dali::BitmapLoader::IsLoaded()
 {
   return GetImplementation(*this).IsLoaded();
 }
+void Dali::BitmapLoader::WaitForLoading()
+{
+  GetImplementation(*this).WaitForLoading();
+}
+
+BitmapLoader Dali::BitmapLoader::GetLatestCreated()
+{
+  return gBitmapLoader;
+}
+
+void Dali::BitmapLoader::ResetLatestCreated()
+{
+  gBitmapLoader.Reset();
+}
 
 } // Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-bitmap-loader.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-bitmap-loader.h
new file mode 100644 (file)
index 0000000..141903b
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef __DALI_TOOLKIT_BITMAP_LOADER_H__
+#define __DALI_TOOLKIT_BITMAP_LOADER_H__
+/*
+ * Copyright (c) 2016 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define __DALI_BITMAP_LOADER_H__
+
+#include <string>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/images/pixel.h>
+#include <dali/public-api/images/image-operations.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/devel-api/images/pixel-data.h>
+
+namespace Dali
+{
+namespace Internal
+{
+class BitmapLoader;
+}
+
+class DALI_IMPORT_API BitmapLoader : public BaseHandle
+{
+public:
+
+  static BitmapLoader New( const std::string& url,
+                           ImageDimensions size = ImageDimensions( 0, 0 ),
+                           FittingMode::Type fittingMode = FittingMode::DEFAULT,
+                           SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR,
+                           bool orientationCorrection = true);
+  BitmapLoader();
+  ~BitmapLoader();
+  BitmapLoader(const BitmapLoader& handle);
+  BitmapLoader& operator=(const BitmapLoader& rhs);
+
+public:
+  void Load();
+  bool IsLoaded();
+  std::string GetUrl() const;
+  PixelDataPtr GetPixelData() const;
+
+  void WaitForLoading();
+  static BitmapLoader GetLatestCreated(); // return the latest created BitmapLoader
+  static void ResetLatestCreated();
+
+public: // Not intended for application developers
+
+  explicit DALI_INTERNAL BitmapLoader(Internal::BitmapLoader*);
+};
+
+} // Dali
+
+#endif /* __DALI_TOOLKIT_BITMAP_LOADER_H__ */
index f5a2d96..d524b81 100644 (file)
@@ -483,6 +483,7 @@ int UtcDaliControlRendererGetPropertyMap5(void)
   propertyMap.Insert( "desiredHeight",   30 );
   propertyMap.Insert( "fittingMode",   "FIT_HEIGHT" );
   propertyMap.Insert( "samplingMode",   "BOX_THEN_NEAREST" );
+  propertyMap.Insert( "synchronousLoading",   true );
 
   ControlRenderer imageRenderer = factory.GetControlRenderer(propertyMap);
   DALI_TEST_CHECK( imageRenderer );
@@ -515,6 +516,10 @@ int UtcDaliControlRendererGetPropertyMap5(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<int>() == 30 );
 
+  value = resultMap.Find( "synchronousLoading",   Property::BOOLEAN );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<bool>() == true );
+
   // Get an image renderer with an image handle, and test the default property values
   Image image = ResourceImage::New(TEST_IMAGE_FILE_NAME, ImageDimensions(100, 200));
   imageRenderer = factory.GetControlRenderer(image);
@@ -544,6 +549,10 @@ int UtcDaliControlRendererGetPropertyMap5(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<int>() == 200 );
 
+  value = resultMap.Find( "synchronousLoading",   Property::BOOLEAN );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<bool>() == false );
+
   END_TEST;
 }
 
index 67f054c..5955748 100644 (file)
@@ -18,6 +18,8 @@
 // Need to override adaptor classes for toolkit test harness, so include
 // test harness headers before dali headers.
 #include <dali-toolkit-test-suite-utils.h>
+#include <toolkit-bitmap-loader.h>
+#include <toolkit-event-thread-callback.h>
 
 #include <dali-toolkit/dali-toolkit.h>
 #include <dali/devel-api/scripting/scripting.h>
@@ -73,6 +75,11 @@ const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
 const char* TEST_IMAGE_FILE_NAME =  "gallery_image_01.jpg";
 const char* TEST_IMAGE_FILE_NAME2 =  "gallery_image_02.jpg";
 
+// resolution: 34*34, pixel format: RGBA8888
+static const char* gImage_34_RGBA = TEST_RESOURCE_DIR "/icon-edit.png";
+// resolution: 600*600, pixel format: RGB888
+static const char* gImage_600_RGB = TEST_RESOURCE_DIR "/test-image-600.jpg";
+
 void TestImage( ImageView imageView, BufferImage image )
 {
   Property::Value value = imageView.GetProperty( imageView.GetPropertyIndex( "image" ) );
@@ -356,6 +363,124 @@ int UtcDaliImageViewSetGetProperty03(void)
   END_TEST;
 }
 
+int UtcDaliImageViewAsyncLoadingWithoutAltasing(void)
+{
+  ToolkitTestApplication application;
+
+  // Async loading, no atlasing for big size image
+  ImageView imageView = ImageView::New( gImage_600_RGB );
+
+  // By default, Aysnc loading is used
+  Stage::GetCurrent().Add( imageView );
+  application.SendNotification();
+  application.Render(16);
+  application.Render(16);
+  application.SendNotification();
+
+  // BitmapLoader is not used
+  BitmapLoader loader = BitmapLoader::GetLatestCreated();
+  DALI_TEST_CHECK( !loader );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewAsyncLoadingWithAltasing(void)
+{
+  ToolkitTestApplication application;
+
+  //Async loading, automatic atlasing for small size image
+  TraceCallStack& callStack = application.GetGlAbstraction().GetTextureTrace();
+  callStack.Reset();
+  callStack.Enable(true);
+
+  ImageView imageView = ImageView::New( gImage_34_RGBA, ImageDimensions( 34, 34 ) );
+
+  // By default, Aysnc loading is used
+  // loading is not started if the actor is offStage
+  BitmapLoader loader = BitmapLoader::GetLatestCreated();
+  DALI_TEST_CHECK( !loader );
+
+  Stage::GetCurrent().Add( imageView );
+  application.SendNotification();
+  application.Render(16);
+  application.Render(16);
+  application.SendNotification();
+
+  // loading started
+  loader = BitmapLoader::GetLatestCreated();
+  DALI_TEST_CHECK( loader );
+
+  // worker thread is created
+  EventThreadCallback* eventTrigger = EventThreadCallback::Get();
+  DALI_TEST_CHECK( eventTrigger );
+
+  loader.WaitForLoading();// waiting until the image to be loaded
+  DALI_TEST_CHECK( loader.IsLoaded() );
+
+  CallbackBase* callback = eventTrigger->GetCallback();
+  CallbackBase::Execute( *callback );
+
+  application.SendNotification();
+  application.Render(16);
+
+  callStack.Enable(false);
+
+  DALI_TEST_CHECK(  callStack.FindMethodAndParams("TexSubImage2D", "0, 0, 34, 34" ) );
+
+
+  END_TEST;
+}
+
+int UtcDaliImageViewSyncLoading(void)
+{
+  ToolkitTestApplication application;
+
+  Property::Map syncLoadingMap;
+  syncLoadingMap[ "synchronousLoading" ] = true;
+
+  // Sync loading, no atlasing for big size image
+  {
+    ImageView imageView = ImageView::New( gImage_600_RGB );
+
+    // Sync loading is used
+    imageView.SetProperty( ImageView::Property::IMAGE, syncLoadingMap );
+
+    // BitmapLoader is used, and the loading is started immediately even the actor is not on stage.
+    BitmapLoader loader = BitmapLoader::GetLatestCreated();
+    DALI_TEST_CHECK( loader );
+  }
+
+  // Sync loading, automatic atlasing for small size image
+  {
+    BitmapLoader::ResetLatestCreated();
+    TraceCallStack& callStack = application.GetGlAbstraction().GetTextureTrace();
+    callStack.Reset();
+    callStack.Enable(true);
+
+    ImageView imageView = ImageView::New( );
+    // Sync loading is used
+    syncLoadingMap[ "url" ] = gImage_34_RGBA;
+    syncLoadingMap[ "desiredHeight" ] = 34;
+    syncLoadingMap[ "desiredWidth" ] = 34;
+    imageView.SetProperty( ImageView::Property::IMAGE, syncLoadingMap );
+
+    // loading is started even if the actor is offStage
+    BitmapLoader loader = BitmapLoader::GetLatestCreated();
+    DALI_TEST_CHECK( loader );
+
+    loader.WaitForLoading();
+
+    DALI_TEST_CHECK( loader.IsLoaded() );
+
+    Stage::GetCurrent().Add( imageView );
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_CHECK(  callStack.FindMethodAndParams("TexSubImage2D", "0, 0, 34, 34" ) );
+  }
+
+  END_TEST;
+}
+
 int UtcDaliImageViewSizeWithBackground(void)
 {
   ToolkitTestApplication application;
index e50e961..03229f9 100644 (file)
@@ -44,8 +44,7 @@ DALI_TYPE_REGISTRATION_END()
 using namespace Dali;
 
 ImageView::ImageView()
-: Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ),
-  mPremultipledAlphaEnabled( false )
+: Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) )
 {
 }
 
@@ -305,10 +304,10 @@ void ImageView::SetProperty( BaseObject* object, Property::Index index, const Pr
 
       case Toolkit::ImageView::Property::PRE_MULTIPLIED_ALPHA:
       {
-        bool IsPre;
-        if( value.Get( IsPre ) )
+        bool isPre;
+        if( value.Get( isPre ) )
         {
-          GetImpl(imageView).EnablePreMultipliedAlpha( IsPre );
+          GetImpl(imageView).EnablePreMultipliedAlpha( isPre );
         }
         break;
       }
index c598c26..fcc0c63 100644 (file)
@@ -164,8 +164,6 @@ private:
   std::string      mUrl;          ///< the url for the image if the image came from a URL, empty otherwise
   Image            mImage;        ///< the Image if the image came from a Image, null otherwise
   Property::Map    mPropertyMap;  ///< the Property::Map if the image came from a Property::Map, empty otherwise
-
-  bool             mPremultipledAlphaEnabled; ///< Flag indicating whether the Pre-multiplied Alpha Blending is required
 };
 
 } // namespace Internal
index 2428715..5092075 100644 (file)
@@ -39,7 +39,8 @@ struct Internal::ControlRenderer::Impl
   {
     IS_ON_STAGE = 1,
     IS_FROM_CACHE = 1 << 1,
-    IS_PREMULTIPLIED_ALPHA = 1 << 2
+    IS_PREMULTIPLIED_ALPHA = 1 << 2,
+    IS_SYNCHRONOUS_RESOURCE_LOADING = 1 << 3
   };
 
   struct CustomShader
index 42d9634..2009f8a 100644 (file)
@@ -137,7 +137,15 @@ void ControlRenderer::SetOffStage( Actor& actor )
 
 void ControlRenderer::EnablePreMultipliedAlpha( bool preMultipled )
 {
-  mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
+  if(preMultipled)
+  {
+    mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
+  }
+  else
+  {
+    mImpl->mFlags &= ~Impl::IS_PREMULTIPLIED_ALPHA;
+  }
+
   if( mImpl->mRenderer )
   {
     mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, preMultipled);
index 90dd616..af155f7 100644 (file)
@@ -22,6 +22,8 @@
 #include <cstring> // for strncasecmp
 #include <dali/public-api/images/resource-image.h>
 #include <dali/public-api/images/native-image.h>
+#include <dali/devel-api/images/atlas.h>
+#include <dali/devel-api/adaptor-framework/bitmap-loader.h>
 #include <dali/integration-api/debug.h>
 
 // INTERNAL HEADER
@@ -51,6 +53,7 @@ const char * const IMAGE_FITTING_MODE( "fittingMode" );
 const char * const IMAGE_SAMPLING_MODE( "samplingMode" );
 const char * const IMAGE_DESIRED_WIDTH( "desiredWidth" );
 const char * const IMAGE_DESIRED_HEIGHT( "desiredHeight" );
+const char * const SYNCHRONOUS_LOADING( "synchronousLoading" );
 
 // fitting modes
 const char * const SHRINK_TO_FIT("SHRINK_TO_FIT");
@@ -248,6 +251,29 @@ void ImageRenderer::DoInitialize( Actor& actor, const Property::Map& propertyMap
     }
 
     mDesiredSize = ImageDimensions( desiredWidth, desiredHeight );
+
+  }
+
+  Property::Value* syncLoading = propertyMap.Find( SYNCHRONOUS_LOADING );
+  if( syncLoading )
+  {
+    bool sync;
+    syncLoading->Get( sync );
+    if( sync )
+    {
+      mImpl->mFlags |= Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
+    }
+    else
+    {
+      mImpl->mFlags &= ~Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
+    }
+  }
+
+  // if sync loading is required, the loading should start immediately when new image url is set or the actor is off stage
+  // ( for on-stage actor with image url unchanged, resource loading is already finished)
+  if( ( !mImpl->mRenderer || imageURLValue) && IsSynchronousResourceLoading() )
+  {
+    DoSynchronousResourceLoading();
   }
 
   // remove old renderer if exit
@@ -354,10 +380,7 @@ Renderer ImageRenderer::CreateRenderer() const
     }
   }
 
-  TextureSet textureSet = TextureSet::New();
-
   Renderer renderer = Renderer::New( geometry, shader );
-  renderer.SetTextures( textureSet );
 
   return renderer;
 }
@@ -378,20 +401,13 @@ Renderer ImageRenderer::CreateNativeImageRenderer() const
   else
   {
     geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
-    if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() )
+    shader  = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
+                           mNativeFragmentShaderCode,
+                           mImpl->mCustomShader->mHints );
+    if( mImpl->mCustomShader->mVertexShader.empty() )
     {
-      shader  = Shader::New( VERTEX_SHADER, mNativeFragmentShaderCode );
-    }
-    else
-    {
-      shader  = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
-                             mNativeFragmentShaderCode,
-                             mImpl->mCustomShader->mHints );
-      if( mImpl->mCustomShader->mVertexShader.empty() )
-      {
-        shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
-        shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
-      }
+      shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
+      shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
     }
   }
 
@@ -402,6 +418,82 @@ Renderer ImageRenderer::CreateNativeImageRenderer() const
   return renderer;
 }
 
+
+bool ImageRenderer::IsSynchronousResourceLoading() const
+{
+  return mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
+}
+
+void ImageRenderer::DoSynchronousResourceLoading()
+{
+  if( !mImageUrl.empty() )
+  {
+    BitmapLoader loader = BitmapLoader::New( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode );
+    loader.Load();
+    mPixels = loader.GetPixelData();
+  }
+}
+
+Image ImageRenderer::LoadImage( const std::string& url, bool synchronousLoading )
+{
+  if( synchronousLoading )
+  {
+    if( !mPixels )
+    {
+      // use broken image
+      return RendererFactory::GetBrokenRendererImage();
+    }
+    Atlas image = Atlas::New( mPixels->GetWidth(), mPixels->GetHeight(), mPixels->GetPixelFormat() );
+    image.Upload( mPixels, 0, 0 );
+    return image;
+  }
+  else
+  {
+    ResourceImage resourceImage = Dali::ResourceImage::New( url, mDesiredSize, mFittingMode, mSamplingMode );
+    resourceImage.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded );
+    return resourceImage;
+  }
+}
+
+TextureSet ImageRenderer::CreateTextureSet( Vector4& textureRect, const std::string& url, bool synchronousLoading )
+{
+  TextureSet textureSet;
+  textureRect = FULL_TEXTURE_RECT;
+  if( synchronousLoading )
+  {
+    if( !mPixels )
+    {
+      // use broken image
+      textureSet = TextureSet::New();
+      textureSet.SetImage( 0u, RendererFactory::GetBrokenRendererImage() );
+    }
+    else
+    {
+      textureSet = mAtlasManager.Add(textureRect, mPixels );
+      if( !textureSet ) // big image, no atlasing
+      {
+        Atlas image = Atlas::New( mPixels->GetWidth(), mPixels->GetHeight(), mPixels->GetPixelFormat() );
+        image.Upload( mPixels, 0, 0 );
+        textureSet = TextureSet::New();
+        textureSet.SetImage( 0u, image );
+      }
+    }
+  }
+  else
+  {
+    textureSet = mAtlasManager.Add(textureRect, url, mDesiredSize, mFittingMode, mSamplingMode );
+    if( !textureSet ) // big image, no atlasing
+    {
+      ResourceImage resourceImage = Dali::ResourceImage::New( url, mDesiredSize, mFittingMode, mSamplingMode );
+      resourceImage.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded );
+      textureSet = TextureSet::New();
+      textureSet.SetImage( 0u, resourceImage );
+    }
+  }
+
+  return textureSet;
+}
+
 void ImageRenderer::InitializeRenderer( const std::string& imageUrl )
 {
   if( imageUrl.empty() )
@@ -420,25 +512,15 @@ void ImageRenderer::InitializeRenderer( const std::string& imageUrl )
     if( !mImpl->mRenderer )
     {
       Vector4 atlasRect;
-      TextureSet textureSet = mAtlasManager.Add(atlasRect, imageUrl, mDesiredSize, mFittingMode, mSamplingMode );
-      if( textureSet )
+      TextureSet textureSet = CreateTextureSet(atlasRect, imageUrl, IsSynchronousResourceLoading() );
+      Geometry geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
+      Shader shader( GetImageShader(mFactoryCache) );
+      mImpl->mRenderer = Renderer::New( geometry, shader );
+      mImpl->mRenderer.SetTextures( textureSet );
+      if( atlasRect != FULL_TEXTURE_RECT )
       {
-        Geometry geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
-        Shader shader( GetImageShader(mFactoryCache) );
-        mImpl->mRenderer = Renderer::New( geometry, shader );
-        mImpl->mRenderer.SetTextures( textureSet );
         mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, atlasRect );
       }
-      else // big image, atlasing is not applied
-      {
-        mImpl->mRenderer = CreateRenderer();
-
-        ResourceImage image = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode );
-        image.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded );
-        TextureSet textureSet = mImpl->mRenderer.GetTextures();
-        textureSet.SetImage( 0u, image );
-      }
-
       mFactoryCache.SaveRenderer( imageUrl, mImpl->mRenderer );
     }
 
@@ -450,9 +532,8 @@ void ImageRenderer::InitializeRenderer( const std::string& imageUrl )
 
     mImpl->mFlags &= ~Impl::IS_FROM_CACHE;
     mImpl->mRenderer = CreateRenderer();
-    ResourceImage resourceImage = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode );
-    resourceImage.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded );
-    ApplyImageToSampler( resourceImage );
+    Image image = LoadImage( imageUrl, IsSynchronousResourceLoading() );
+    ApplyImageToSampler( image );
   }
 }
 
@@ -502,6 +583,9 @@ void ImageRenderer::DoCreatePropertyMap( Property::Map& map ) const
 {
   map.Clear();
   map.Insert( RENDERER_TYPE, IMAGE_RENDERER );
+
+  bool sync = IsSynchronousResourceLoading();
+  map.Insert( SYNCHRONOUS_LOADING, sync );
   if( !mImageUrl.empty() )
   {
     map.Insert( IMAGE_URL_NAME, mImageUrl );
@@ -618,6 +702,11 @@ void ImageRenderer::SetImage( Actor& actor, const std::string& imageUrl, ImageDi
     mSamplingMode = samplingMode;
     mImage.Reset();
 
+    if( IsSynchronousResourceLoading() )
+    {
+      DoSynchronousResourceLoading();
+    }
+
     if( mImpl->mRenderer )
     {
       if( GetIsFromCache() ) // if renderer is from cache, remove the old one
@@ -641,8 +730,7 @@ void ImageRenderer::SetImage( Actor& actor, const std::string& imageUrl, ImageDi
       }
       else // if renderer is not from cache, reuse the same renderer and only change the texture
       {
-        ResourceImage image = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode );
-        image.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded );
+        Image image = LoadImage( imageUrl, IsSynchronousResourceLoading() );
         ApplyImageToSampler( image );
       }
     }
@@ -733,10 +821,12 @@ void ImageRenderer::ApplyImageToSampler( const Image& image )
   if( image )
   {
     TextureSet textureSet = mImpl->mRenderer.GetTextures();
-    if( textureSet )
+    if( !textureSet )
     {
-      textureSet.SetImage( 0u, image );
+      textureSet = TextureSet::New();
+      mImpl->mRenderer.SetTextures( textureSet );
     }
+    textureSet.SetImage( 0u, image );
   }
 }
 
@@ -795,7 +885,6 @@ void ImageRenderer::SetNativeFragmentShaderCode( Dali::NativeImage& nativeImage
   {
     mNativeFragmentShaderCode.replace( mNativeFragmentShaderCode.find( DEFAULT_SAMPLER_TYPENAME ), strlen( DEFAULT_SAMPLER_TYPENAME ), customSamplerTypename );
   }
-
 }
 
 } // namespace Internal
index da7e100..c63a073 100644 (file)
@@ -46,13 +46,14 @@ typedef IntrusivePtr< ImageRenderer > ImageRendererPtr;
  *
  * The following properties are optional
  *
- * | %Property Name          | Type             |
- * |-------------------------|------------------|
+ * | %Property Name     | Type             |
+ * |--------------------|------------------|
  * | url                | STRING           |
  * | fittingMode        | STRING           |
  * | samplingMode       | STRING           |
  * | desiredWidth       | INT              |
  * | desiredHeight      | INT              |
+ * | synchronousLoading | BOOLEAN          |
  *
  * where imageFittingMode should be one of the following fitting modes:
  *   "SHRINK_TO_FIT"
@@ -145,7 +146,7 @@ public:
    * The renderer will load the Image asynchronously when the associated actor is put on stage, and destroy the image when it is off stage
    *
    * @param[in] actor The Actor the renderer is applied to if, empty if the renderer has not been applied to any Actor
-   * @param[in] imageUrl The URL to to image resource to use
+   * @param[in] imageUrl The URL of the image resource to use
    * @param[in] size The width and height to fit the loaded image to.
    * @param[in] fittingMode The FittingMode of the resource to load
    * @param[in] samplingMode The SamplingMode of the resource to load
@@ -202,6 +203,32 @@ private:
   Renderer CreateNativeImageRenderer() const;
 
   /**
+   * @brief Query whether resources requires to be loaded synchronously.
+   * @return Returns true if synchronoud resource loading is required, false otherwise.
+   */
+  bool IsSynchronousResourceLoading() const;
+
+  /**
+   * @brief Do the synchronous resource loading
+   */
+  void DoSynchronousResourceLoading();
+
+  /**
+   * Load the image.
+   * @param[in] url The URL of the image resource to use.
+   * @param[in] synchronousLoading If true, the resource is loaded synchronously, otherwise asynchronously.
+   */
+  Image LoadImage( const std::string& url, bool synchronousLoading );
+
+  /**
+   * Load the image and create a texture set to hold the texture, with automatic atlasing applied.
+   * @param [out] textureRect The texture area of the resource image in the atlas.
+   * @param[in] url The URL of the image resource to use.
+   * @param[in] synchronousLoading If true, the resource is loaded synchronously, otherwise asynchronously.
+   */
+  TextureSet CreateTextureSet( Vector4& textureRect, const std::string& url, bool synchronousLoading );
+
+  /**
    * Callback function of image resource loading succeed
    * @param[in] image The Image content that we attempted to load from mImageUrl
    */
@@ -226,6 +253,7 @@ private:
 private:
   Image mImage;
   ImageAtlasManager& mAtlasManager;
+  PixelDataPtr mPixels;
 
   std::string mImageUrl;
   Dali::ImageDimensions mDesiredSize;
index 14e3427..bc401f1 100644 (file)
@@ -94,12 +94,13 @@ public:
        */
       PRE_MULTIPLIED_ALPHA,
 
+
       // Animatable properties
 
       /**
        * @brief name "pixelArea", type Vector4
        * @details Pixel area is a relative value with the whole image area as [0.0, 0.0, 1.0, 1.0].
-       * @SINCE_1_0.18
+       * @SINCE_1_1.18
        */
       PIXEL_AREA = ANIMATABLE_PROPERTY_START_INDEX,
     };