Async image loading 49/88149/12
authorXiangyin Ma <x1.ma@samsung.com>
Wed, 24 Aug 2016 16:05:29 +0000 (17:05 +0100)
committerXiangyin Ma <x1.ma@samsung.com>
Mon, 10 Oct 2016 15:06:26 +0000 (16:06 +0100)
Change-Id: If5bb546217017a055e70f4a0b55f4d1f6cfa9b85

21 files changed:
automated-tests/src/dali-toolkit/CMakeLists.txt
automated-tests/src/dali-toolkit/utc-Dali-AsyncImageLoader.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ImageAtlas.cpp
automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp
build/tizen/dali-toolkit/Makefile.am
dali-toolkit/devel-api/file.list
dali-toolkit/devel-api/image-loader/async-image-loader.cpp [new file with mode: 0644]
dali-toolkit/devel-api/image-loader/async-image-loader.h [new file with mode: 0644]
dali-toolkit/devel-api/image-loader/image-atlas.cpp [moved from dali-toolkit/devel-api/image-atlas/image-atlas.cpp with 91% similarity]
dali-toolkit/devel-api/image-loader/image-atlas.h [moved from dali-toolkit/devel-api/image-atlas/image-atlas.h with 88% similarity]
dali-toolkit/internal/file.list
dali-toolkit/internal/image-loader/async-image-loader-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/image-loader/async-image-loader-impl.h [new file with mode: 0644]
dali-toolkit/internal/image-loader/atlas-packer.cpp [moved from dali-toolkit/internal/image-atlas/atlas-packer.cpp with 88% similarity]
dali-toolkit/internal/image-loader/atlas-packer.h [moved from dali-toolkit/internal/image-atlas/atlas-packer.h with 100% similarity]
dali-toolkit/internal/image-loader/image-atlas-impl.cpp [moved from dali-toolkit/internal/image-atlas/image-atlas-impl.cpp with 69% similarity]
dali-toolkit/internal/image-loader/image-atlas-impl.h [moved from dali-toolkit/internal/image-atlas/image-atlas-impl.h with 69% similarity]
dali-toolkit/internal/image-loader/image-load-thread.cpp [moved from dali-toolkit/internal/image-atlas/image-load-thread.cpp with 52% similarity]
dali-toolkit/internal/image-loader/image-load-thread.h [moved from dali-toolkit/internal/image-atlas/image-load-thread.h with 59% similarity]
dali-toolkit/internal/visuals/image-atlas-manager.cpp
dali-toolkit/internal/visuals/image-atlas-manager.h

index 3b39bd0..d6ad543 100644 (file)
@@ -54,6 +54,7 @@ SET(TC_SOURCES
    utc-Dali-DebugRendering.cpp
    utc-Dali-ImageAtlas.cpp
    utc-Dali-VideoView.cpp
+   utc-Dali-AsyncImageLoader.cpp
 )
 
 # Append list of test harness files (Won't get parsed for test cases)
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-AsyncImageLoader.cpp b/automated-tests/src/dali-toolkit/utc-Dali-AsyncImageLoader.cpp
new file mode 100644 (file)
index 0000000..e85d90f
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * 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.
+ *
+ */
+#include <stdlib.h>
+#include <unistd.h>
+#include <dali/dali.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <toolkit-event-thread-callback.h>
+#include <dali-toolkit/devel-api/image-loader/async-image-loader.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+// resolution: 34*34, pixel format: RGBA8888
+static const char* gImage_34_RGBA = TEST_RESOURCE_DIR "/icon-edit.png";
+// resolution: 50*50, pixel format: RGBA8888
+static const char* gImage_50_RGBA = TEST_RESOURCE_DIR "/icon-delete.png";
+// resolution: 128*128, pixel format: RGB888
+static const char* gImage_128_RGB = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
+
+// for testing the ImageLoadedSignal
+class ImageLoadedSignalVerifier : public ConnectionTracker
+{
+public:
+
+  ImageLoadedSignalVerifier()
+  : mCount( 0 )
+  {}
+
+  virtual ~ImageLoadedSignalVerifier()
+  {}
+
+  void ImageLoaded( uint32_t id, PixelData pixelData )
+  {
+    mIDs.push_back( id );
+    mPixelDataList.push_back( pixelData );
+    mCount++;
+  }
+
+  int LoadedImageCount()
+  {
+    return mCount;
+  }
+
+  bool Verify( uint32_t id, uint32_t width, uint32_t height )
+  {
+    int size = mIDs.size();
+    for( int i = 0; i<size; i++  )
+    {
+      if( mIDs[i] == id )
+      {
+        return mPixelDataList[i].GetWidth() == width
+            && mPixelDataList[i].GetHeight() == height;
+      }
+    }
+
+    return false;
+  }
+
+private:
+
+  int mCount;
+
+  std::vector<uint32_t> mIDs;
+  std::vector<PixelData> mPixelDataList;
+};
+
+
+} // anonymous namespace
+
+void dali_async_image_loader_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_async_image_loader_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliImageAtlasNew01(void)
+{
+  ToolkitTestApplication application;
+
+  //invoke default handle constructor
+  AsyncImageLoader loader;
+
+  DALI_TEST_CHECK( !loader );
+
+  // initialise handle
+  loader = AsyncImageLoader::New();
+  DALI_TEST_CHECK( loader );
+
+  END_TEST;
+}
+
+int UtcDaliAsyncImageLoaderCopyConstructor(void)
+{
+  ToolkitTestApplication application;
+
+  AsyncImageLoader loader = AsyncImageLoader::New( );
+  DALI_TEST_CHECK( loader );
+
+  AsyncImageLoader loaderCopy(loader);
+  DALI_TEST_CHECK( loaderCopy );
+
+  END_TEST;
+}
+
+int UtcDaliAsyncImageLoaderAssignmentOperator(void)
+{
+  ToolkitTestApplication application;
+
+  AsyncImageLoader loader = AsyncImageLoader::New();
+  DALI_TEST_CHECK( loader );
+
+  AsyncImageLoader loader2;
+  DALI_TEST_CHECK( !loader2 );
+
+  loader2 = loader;
+  DALI_TEST_CHECK( loader2 );
+  DALI_TEST_CHECK( loader == loader2 ); // the two handles are pointing to the same object.
+
+  END_TEST;
+}
+
+int UtcDaliAsyncImageLoaderLoadAndLoadedSignal(void)
+{
+  ToolkitTestApplication application;
+
+  AsyncImageLoader loader = AsyncImageLoader::New();
+  ImageLoadedSignalVerifier loadedSignalVerifier;
+
+  loader.ImageLoadedSignal().Connect( &loadedSignalVerifier, &ImageLoadedSignalVerifier::ImageLoaded );
+
+  loader.Load( gImage_34_RGBA );
+  uint32_t id02 = loader.Load( gImage_50_RGBA, ImageDimensions( 25, 25 ) );
+  uint32_t id03 = loader.Load( gImage_128_RGB, ImageDimensions( 100, 100 ), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, true );
+
+  EventThreadCallback* eventTrigger = EventThreadCallback::Get();
+  CallbackBase* callback = eventTrigger->GetCallback();
+
+  eventTrigger->WaitingForTrigger( 3 );// waiting until all three images are loaded
+
+  CallbackBase::Execute( *callback );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( loadedSignalVerifier.LoadedImageCount() == 3 );
+  DALI_TEST_CHECK( loadedSignalVerifier.Verify( id02, 25, 25 ) );
+  DALI_TEST_CHECK( loadedSignalVerifier.Verify( id03, 100, 100 ) );
+
+  END_TEST;
+}
+
+int UtcDaliAsyncImageLoaderCancel(void)
+{
+  ToolkitTestApplication application;
+
+  AsyncImageLoader loader = AsyncImageLoader::New();
+  ImageLoadedSignalVerifier loadedSignalVerifier;
+
+  loader.ImageLoadedSignal().Connect( &loadedSignalVerifier, &ImageLoadedSignalVerifier::ImageLoaded );
+
+  uint32_t id01 = loader.Load( gImage_34_RGBA, ImageDimensions( 34, 34 ) );
+  uint32_t id02 = loader.Load( gImage_50_RGBA, ImageDimensions( 25, 25 ) );
+  uint32_t id03 = loader.Load( gImage_128_RGB, ImageDimensions( 100, 100 ), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, true );
+
+  // cancel the loading of the second image
+  DALI_TEST_CHECK( loader.Cancel( id02 ) );
+
+  EventThreadCallback* eventTrigger = EventThreadCallback::Get();
+  CallbackBase* callback = eventTrigger->GetCallback();
+
+  eventTrigger->WaitingForTrigger( 2 );// waiting until first and third images are loaded
+
+  CallbackBase::Execute( *callback );
+
+  DALI_TEST_CHECK( ! loader.Cancel( id03 ) ); // can not cancel a task that is already implemeted
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( loadedSignalVerifier.LoadedImageCount() == 2 );
+
+  DALI_TEST_CHECK( loadedSignalVerifier.Verify( id01, 34, 34 ) );  // first image is successfully loaded
+  DALI_TEST_CHECK( !loadedSignalVerifier.Verify( id02, 25, 25 ) ); // second image is not loaded
+  DALI_TEST_CHECK( loadedSignalVerifier.Verify( id03, 100, 100 ) ); // third image is successfully loaded
+
+  END_TEST;
+}
+
+int UtcDaliAsyncImageLoaderCancelAll(void)
+{
+  ToolkitTestApplication application;
+
+  AsyncImageLoader loader = AsyncImageLoader::New();
+  ImageLoadedSignalVerifier loadedSignalVerifier;
+
+  loader.ImageLoadedSignal().Connect( &loadedSignalVerifier, &ImageLoadedSignalVerifier::ImageLoaded );
+
+  uint32_t id01 = loader.Load( gImage_34_RGBA, ImageDimensions( 34, 34 ) );
+  uint32_t id02 = loader.Load( gImage_50_RGBA, ImageDimensions( 25, 25 ) );
+
+  // cancel the loading of the first and second image
+  loader.CancelAll();
+
+  uint32_t id03 = loader.Load( gImage_128_RGB, ImageDimensions( 100, 100 ), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, true );
+
+  EventThreadCallback* eventTrigger = EventThreadCallback::Get();
+  CallbackBase* callback = eventTrigger->GetCallback();
+
+  eventTrigger->WaitingForTrigger( 1 );// waiting until the third images is loaded
+
+  CallbackBase::Execute( *callback );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( loadedSignalVerifier.LoadedImageCount() == 1 );
+
+  DALI_TEST_CHECK( !loadedSignalVerifier.Verify( id01, 34, 34 ) );  // first image is not loaded
+  DALI_TEST_CHECK( !loadedSignalVerifier.Verify( id02, 25, 25 ) ); // second image is not loaded
+  DALI_TEST_CHECK( loadedSignalVerifier.Verify( id03, 100, 100 ) ); // third image is successfully loaded
+
+  END_TEST;
+}
+
+
index a8fa8cc..a945850 100644 (file)
@@ -20,8 +20,7 @@
 #include <dali/dali.h>
 #include <dali-toolkit-test-suite-utils.h>
 #include <toolkit-event-thread-callback.h>
-#include <dali/devel-api/images/atlas.h>
-#include <dali-toolkit/devel-api/image-atlas/image-atlas.h>
+#include <dali-toolkit/devel-api/image-loader/image-atlas.h>
 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
 
 using namespace Dali;
@@ -120,15 +119,31 @@ int UtcDaliImageAtlasGetAtlas(void)
   ToolkitTestApplication application;
 
   ImageAtlas atlas = ImageAtlas::New( 32, 32 );
-  Image image = atlas.GetAtlas();
+  Texture image = atlas.GetAtlas();
 
   // test the atlas created
   DALI_TEST_EQUALS( (bool)image, true, TEST_LOCATION );
   DALI_TEST_CHECK( image.GetHeight() == 32u );
   DALI_TEST_CHECK( image.GetWidth() == 32u );
 
-  Atlas coreAtlas = Atlas::DownCast( image );
-  DALI_TEST_EQUALS( (bool)coreAtlas, true, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliImageAtlasGetOccupancyRate(void)
+{
+  ToolkitTestApplication application;
+
+  ImageAtlas atlas = ImageAtlas::New( 100, 100 );
+
+  DALI_TEST_EQUALS( atlas.GetOccupancyRate(), 0.f, TEST_LOCATION );
+
+  Vector4 textureRect1;
+  atlas.Upload( textureRect1, gImage_34_RGBA, ImageDimensions(34, 34) );
+  DALI_TEST_EQUALS( atlas.GetOccupancyRate(), 34.f*34.f/10000.f, 0.001f, TEST_LOCATION );
+
+  Vector4 textureRect2;
+  atlas.Upload( textureRect2, gImage_50_RGBA, ImageDimensions(50, 50) );
+  DALI_TEST_EQUALS( atlas.GetOccupancyRate(), (34.f*34.f+50.f*50.f)/10000.f, 0.001f, TEST_LOCATION );
 
   END_TEST;
 }
@@ -165,9 +180,6 @@ int UtcDaliImageAtlasUploadP(void)
   unsigned int size = 200;
   ImageAtlas atlas = ImageAtlas::New( size, size );
 
-  EventThreadCallback* eventTrigger = EventThreadCallback::Get();
-  CallbackBase* callback = eventTrigger->GetCallback();
-
   TraceCallStack& callStack = application.GetGlAbstraction().GetTextureTrace();
   callStack.Reset();
   callStack.Enable(true);
@@ -179,6 +191,9 @@ int UtcDaliImageAtlasUploadP(void)
   Vector4 textureRect3;
   atlas.Upload( textureRect3, gImage_128_RGB, ImageDimensions(128, 128) );
 
+  EventThreadCallback* eventTrigger = EventThreadCallback::Get();
+  CallbackBase* callback = eventTrigger->GetCallback();
+
   eventTrigger->WaitingForTrigger( 3 );// waiting until all three images are loaded
 
   CallbackBase::Execute( *callback );
index 424e79d..779259d 100644 (file)
@@ -417,6 +417,7 @@ int UtcDaliImageViewAsyncLoadingWithAltasing(void)
   loader.WaitForLoading();// waiting until the image to be loaded
   DALI_TEST_CHECK( loader.IsLoaded() );
 
+  eventTrigger->WaitingForTrigger( 1 );
   CallbackBase* callback = eventTrigger->GetCallback();
   CallbackBase::Execute( *callback );
 
index 5c6d46c..f31838e 100644 (file)
@@ -109,7 +109,7 @@ develapiprogressbardir =        $(develapicontrolsdir)/progress-bar
 develapishadowviewdir =         $(develapicontrolsdir)/shadow-view
 develapisuperblurviewdir =      $(develapicontrolsdir)/super-blur-view
 develapifocusmanagerdir =       $(develapidir)/focus-manager
-develapiimageatlasdir =         $(develapidir)/image-atlas
+develapiimageloaderdir =         $(develapidir)/image-loader
 develapiscriptingdir =          $(develapidir)/scripting
 develapishadereffectsdir =      $(develapidir)/shader-effects
 develapitransitioneffectsdir =  $(develapidir)/transition-effects
@@ -126,7 +126,7 @@ develapibuilder_HEADERS =           $(devel_api_builder_header_files)
 develapieffectsview_HEADERS =       $(devel_api_effects_view_header_files)
 develapifocusmanager_HEADERS =      $(devel_api_focus_manager_header_files)
 develapigaussianblurview_HEADERS =  $(devel_api_gaussian_blur_view_header_files)
-develapiimageatlas_HEADERS =        $(devel_api_image_atlas_header_files)
+develapiimageloader_HEADERS =       $(devel_api_image_loader_header_files)
 develapimagnifier_HEADERS =         $(devel_api_magnifier_header_files)
 develapipageturnview_HEADERS =      $(devel_api_page_turn_view_header_files)
 develapipopup_HEADERS =             $(devel_api_popup_header_files)
index 80e97ee..7cc6a2c 100755 (executable)
@@ -20,7 +20,8 @@ devel_api_src_files = \
   $(devel_api_src_dir)/controls/text-controls/text-selection-toolbar.cpp \
   $(devel_api_src_dir)/controls/tool-bar/tool-bar.cpp \
   $(devel_api_src_dir)/focus-manager/keyinput-focus-manager.cpp \
-  $(devel_api_src_dir)/image-atlas/image-atlas.cpp \
+  $(devel_api_src_dir)/image-loader/async-image-loader.cpp \
+  $(devel_api_src_dir)/image-loader/image-atlas.cpp \
   $(devel_api_src_dir)/scripting/script.cpp \
   $(devel_api_src_dir)/transition-effects/cube-transition-cross-effect.cpp \
   $(devel_api_src_dir)/transition-effects/cube-transition-effect.cpp \
@@ -75,8 +76,9 @@ devel_api_shadow_view_header_files = \
 devel_api_focus_manager_header_files = \
   $(devel_api_src_dir)/focus-manager/keyinput-focus-manager.h
 
-devel_api_image_atlas_header_files = \
-  $(devel_api_src_dir)/image-atlas/image-atlas.h
+devel_api_image_loader_header_files = \
+  $(devel_api_src_dir)/image-loader/async-image-loader.h \
+  $(devel_api_src_dir)/image-loader/image-atlas.h
 
 devel_api_scripting_header_files = \
   $(devel_api_src_dir)/scripting/script.h \
diff --git a/dali-toolkit/devel-api/image-loader/async-image-loader.cpp b/dali-toolkit/devel-api/image-loader/async-image-loader.cpp
new file mode 100644 (file)
index 0000000..a20ece1
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+// CLASS HEADER
+#include "async-image-loader.h"
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/image-loader/async-image-loader-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+AsyncImageLoader::AsyncImageLoader()
+{
+}
+
+AsyncImageLoader::~AsyncImageLoader()
+{
+}
+
+AsyncImageLoader::AsyncImageLoader( Internal::AsyncImageLoader* impl )
+: BaseHandle( impl )
+{}
+
+AsyncImageLoader::AsyncImageLoader( const AsyncImageLoader& handle )
+: BaseHandle( handle )
+{
+}
+
+AsyncImageLoader& AsyncImageLoader::operator=( const AsyncImageLoader& handle )
+{
+  BaseHandle::operator=(handle);
+  return *this;
+}
+
+AsyncImageLoader AsyncImageLoader::New()
+{
+  IntrusivePtr<Internal::AsyncImageLoader> internal = Internal::AsyncImageLoader::New();
+   return AsyncImageLoader( internal.Get() );
+}
+
+uint32_t AsyncImageLoader::Load( const std::string& url )
+{
+  return GetImplementation(*this).Load( url, ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true );
+}
+
+uint32_t AsyncImageLoader::Load( const std::string& url, ImageDimensions size )
+{
+  return GetImplementation(*this).Load( url, size, FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true );
+}
+
+uint32_t AsyncImageLoader::Load( const std::string& url,
+                                 ImageDimensions size,
+                                 FittingMode::Type fittingMode,
+                                 SamplingMode::Type samplingMode,
+                                 bool orientationCorrection )
+{
+  return GetImplementation(*this).Load( url, size, fittingMode, samplingMode, orientationCorrection );
+}
+
+bool AsyncImageLoader::Cancel( uint32_t loadingTaskId)
+{
+  return GetImplementation(*this).Cancel( loadingTaskId );
+}
+
+void AsyncImageLoader::CancelAll()
+{
+  GetImplementation(*this).CancelAll();
+}
+
+AsyncImageLoader::ImageLoadedSignalType& AsyncImageLoader::ImageLoadedSignal()
+{
+  return GetImplementation(*this).ImageLoadedSignal();
+}
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/image-loader/async-image-loader.h b/dali-toolkit/devel-api/image-loader/async-image-loader.h
new file mode 100644 (file)
index 0000000..82a2079
--- /dev/null
@@ -0,0 +1,193 @@
+#ifndef __DALI_TOOLKIT_ASYNC_IMAGE_LOADER_H__
+#define __DALI_TOOLKIT_ASYNC_IMAGE_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.
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/images/image-operations.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+class PixelData;
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class AsyncImageLoader;
+}
+
+/**
+ *@brief The AysncImageLoader is used to load pixel data from the URL asynchronously.
+ *
+ * The images are loaded in a worker thread to avoid blocking the main event thread.
+ *
+ * Each load call is assigned with an ID, connect to the ImageLoadedSignal and receive the corresponding pixel data by comparing the ID.
+ *
+ * To make sure the signal is always received, the signal should get connected before invoking the load call.
+ * @code
+ * class MyClass : public ConnectionTracker
+ * {
+ * public:
+ *
+ *   MyCallback( uint32_t id, PixelData pixelData)
+ *   {
+ *     if(id == mId1)
+ *     {
+ *       // use the loaded pixel data from the first image
+ *     }
+ *     else if( id == mId2 )
+ *     {
+ *       // use the loaded pixel data from the second image
+ *     }
+ *   }
+ *
+ *   uint32_t mId1;
+ *   uint32_t mId2;
+ * };
+ *
+ * MyClass myObject;
+ * AsyncImageLoader imageLoader = AsyncImageLoader::New();
+ * // connect the signal here
+ * imageLoader.ImageLoadedSignal().Connect( &myObject, &MyClass::MyCallback );
+ * // then invoke the load calls
+ * testCallback.mId1 = imageLoader.Load( "first_image_url.jpg" );
+ * testCallback.mId2 = imageLoader.Load( "second_image_url.jpg" );
+ *
+ * @endcode
+ */
+class DALI_IMPORT_API AsyncImageLoader : public BaseHandle
+{
+public:
+
+  /**
+   * @brief Type of signal for image loading finished.
+   *
+   * The signal is emit with the load ID and its corresponding loaded pixel data
+   */
+  typedef Signal< void( uint32_t, PixelData ) > ImageLoadedSignalType;
+
+public:
+
+  /**
+   * @brief Constructor which creates an empty AsyncImageLoader handle.
+   *
+   * Use AsyncImageLoader::New() to create an initialised object.
+   */
+  AsyncImageLoader();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~AsyncImageLoader();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @param [in] handle A reference to the copied handle
+   */
+  AsyncImageLoader( const AsyncImageLoader& handle );
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @param [in] handle  A reference to the copied handle
+   * @return A reference to this
+   */
+  AsyncImageLoader& operator=( const AsyncImageLoader& handle );
+
+ /*
+  * @brief Create a new loader to load the image asynchronously in a worker thread.
+  *
+  * @return The image loader.
+  */
+  static AsyncImageLoader New();
+
+  /**
+   * @brief Start a image loading task.
+   *
+   * @param[in] url The URL of the image file to load.
+   * @return The loading task id.
+   */
+  uint32_t Load( const std::string& url );
+  /*
+   * @brief Start a image loading 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.
+   * @return The loading task id.
+   */
+  uint32_t Load( const std::string& url, ImageDimensions size );
+
+  /*
+   * @brief Start a image loading 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.
+   * @param[in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter.
+   * @param[in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size.
+   * @param[in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
+   * @return The loading task id.
+   */
+  uint32_t Load( const std::string& url,
+                 ImageDimensions size,
+                 FittingMode::Type fittingMode,
+                 SamplingMode::Type samplingMode,
+                 bool orientationCorrection );
+
+  /**
+   * @brief Cancel a image loading task if it is still queuing in the work thread.
+   *
+   * @param[in] loadingTaskId The task id returned when invoking the load call.
+   * @return If true, the loading task is removed from the queue, otherwise the loading is already implemented and unable to cancel anymore
+   */
+  bool Cancel( uint32_t loadingTaskId);
+
+  /**
+   * @brief Cancel all the loading tasks in the queue
+   */
+  void CancelAll();
+
+  /**
+   * @brief Signal emit for connected callback functions to get access to the loaded pixel data.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( uint32_t id, PixelData pixelData );
+   * @endcode
+   *
+   * @return A signal object to Connect() with.
+   */
+  ImageLoadedSignalType& ImageLoadedSignal();
+
+public: // Not intended for developer use
+
+  explicit DALI_INTERNAL AsyncImageLoader( Internal::AsyncImageLoader* impl );
+
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* __DALI_TOOLKIT_ASYNC_IMAGE_LOADER_H__ */
@@ -19,7 +19,7 @@
 #include "image-atlas.h"
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/internal/image-atlas/image-atlas-impl.h>
+#include <dali-toolkit/internal/image-loader/image-atlas-impl.h>
 
 namespace Dali
 {
@@ -58,11 +58,17 @@ ImageAtlas ImageAtlas::New(SizeType width, SizeType height,
   return ImageAtlas( internal.Get() );
 }
 
-Image ImageAtlas::GetAtlas()
+Texture ImageAtlas::GetAtlas()
 {
   return GetImplementation( *this ).GetAtlas();
 }
 
+float ImageAtlas::GetOccupancyRate() const
+{
+  return GetImplementation( *this ).GetOccupancyRate();
+}
+
+
 void ImageAtlas::SetBrokenImage( const std::string& brokenImageUrl )
 {
   GetImplementation( *this ).SetBrokenImage( brokenImageUrl );
 #include <string>
 #include <stdint.h>
 #include <dali/public-api/object/base-handle.h>
-#include <dali/public-api/images/image.h>
 #include <dali/public-api/images/image-operations.h>
 #include <dali/public-api/images/pixel.h>
 #include <dali/public-api/images/pixel-data.h>
+#include <dali/public-api/rendering/texture.h>
 
 namespace Dali
 {
@@ -37,10 +37,10 @@ class ImageAtlas;
 }
 
 /**
- * @brief An ImageAtlas is a large image containing multiple smaller images.
+ * @brief An ImageAtlas is a large texture containing multiple smaller images.
  *
- * Only images with url provided are supported for uploading.
- * The image are loaded by a worker thread to avoid blocking the main event thread.
+ * Only images with url provided or pixel data are supported for uploading.
+ * The images are loaded by a worker thread to avoid blocking the main event thread.
  */
 class DALI_IMPORT_API ImageAtlas : public BaseHandle
 {
@@ -91,11 +91,18 @@ public:
   /**
    * @brief Get the atlas image.
    *
-   * This atlas image is still valid after destroying the ImageAtlas object.
+   * This atlas texture is still valid after destroying the ImageAtlas object.
    *
-   * @return the atlas image with type of Dali::Atlas
+   * @return The atlas texture
    */
-  Image GetAtlas();
+  Texture GetAtlas();
+
+  /*
+   * @brief Query what percentage of space is been occupied in the atlas.
+   *
+   * @return The occupancy rate of the atlas.
+   */
+  float GetOccupancyRate() const;
 
   /**
    * @brief Set the broken image which is used to replace the image if loading fails.
index 0b13dfb..7fb2109 100644 (file)
@@ -85,9 +85,10 @@ toolkit_src_files = \
    $(toolkit_src_dir)/filters/emboss-filter.cpp \
    $(toolkit_src_dir)/filters/image-filter.cpp \
    $(toolkit_src_dir)/filters/spread-filter.cpp \
-   $(toolkit_src_dir)/image-atlas/atlas-packer.cpp \
-   $(toolkit_src_dir)/image-atlas/image-atlas-impl.cpp \
-   $(toolkit_src_dir)/image-atlas/image-load-thread.cpp \
+   $(toolkit_src_dir)/image-loader/async-image-loader-impl.cpp \
+   $(toolkit_src_dir)/image-loader/atlas-packer.cpp \
+   $(toolkit_src_dir)/image-loader/image-atlas-impl.cpp \
+   $(toolkit_src_dir)/image-loader/image-load-thread.cpp \
    $(toolkit_src_dir)/styling/style-manager-impl.cpp \
    $(toolkit_src_dir)/text/bidirectional-support.cpp \
    $(toolkit_src_dir)/text/character-set-conversion.cpp \
diff --git a/dali-toolkit/internal/image-loader/async-image-loader-impl.cpp b/dali-toolkit/internal/image-loader/async-image-loader-impl.cpp
new file mode 100644 (file)
index 0000000..d25ea5c
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "async-image-loader-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/bitmap-loader.h>
+#include <dali/integration-api/adaptors/adaptor.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+AsyncImageLoader::AsyncImageLoader()
+: mLoadedSignal(),
+  mLoadThread( new EventThreadCallback( MakeCallback( this, &AsyncImageLoader::ProcessLoadedImage ) ) ),
+  mLoadTaskId( 0 ),
+  mIsLoadThreadStarted( false )
+{
+}
+
+AsyncImageLoader::~AsyncImageLoader()
+{
+  mLoadThread.CancelAll();
+}
+
+IntrusivePtr<AsyncImageLoader> AsyncImageLoader::New()
+{
+  IntrusivePtr<AsyncImageLoader> internal = new AsyncImageLoader();
+  return internal;
+}
+
+uint32_t AsyncImageLoader::Load( const std::string& url,
+                                 ImageDimensions size,
+                                 FittingMode::Type fittingMode,
+                                 SamplingMode::Type samplingMode,
+                                 bool orientationCorrection )
+{
+  if( !mIsLoadThreadStarted )
+  {
+    mLoadThread.Start();
+    mIsLoadThreadStarted = true;
+  }
+
+  BitmapLoader loader = BitmapLoader::New( url, size, fittingMode, samplingMode, orientationCorrection );
+
+  mLoadThread.AddTask( new LoadingTask( ++mLoadTaskId, loader ) );
+
+  return mLoadTaskId;
+}
+
+Toolkit::AsyncImageLoader::ImageLoadedSignalType& AsyncImageLoader::ImageLoadedSignal()
+{
+  return mLoadedSignal;
+}
+
+bool AsyncImageLoader::Cancel( uint32_t loadingTaskId )
+{
+  return mLoadThread.CancelTask( loadingTaskId );
+}
+
+void AsyncImageLoader::CancelAll()
+{
+  mLoadThread.CancelAll();
+}
+
+void AsyncImageLoader::ProcessLoadedImage()
+{
+  while( LoadingTask *next =  mLoadThread.NextCompletedTask() )
+  {
+    mLoadedSignal.Emit( next->id, next->loader.GetPixelData() );
+    delete next;
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/image-loader/async-image-loader-impl.h b/dali-toolkit/internal/image-loader/async-image-loader-impl.h
new file mode 100644 (file)
index 0000000..cb0311c
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef DALI_TOOLKIT_ASYNC_IMAGE_LOADER_IMPL_H__
+#define DALI_TOOLKIT_ASYNC_IMAGE_LOADER_IMPL_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.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/images/pixel-data.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/image-loader/async-image-loader.h>
+#include <dali-toolkit/internal/image-loader/image-load-thread.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class AsyncImageLoader : public BaseObject
+{
+public:
+
+  /**
+   * Constructor
+   */
+  AsyncImageLoader();
+
+  /**
+   * @copydoc Toolkit::AsyncImageLoader::New()
+   */
+  static IntrusivePtr<AsyncImageLoader> New();
+
+  /**
+   * @copydoc Toolkit::AsyncImageLoader::Load( const std::string&, ImageDimensions,FittingMode::Type, SamplingMode::Type, bool )
+   */
+  uint32_t Load( const std::string& url,
+                 ImageDimensions size,
+                 FittingMode::Type fittingMode,
+                 SamplingMode::Type samplingMode,
+                 bool orientationCorrection );
+
+  /**
+   * @copydoc Toolkit::AsyncImageLoader::ImageLoadedSignal
+   */
+  Toolkit::AsyncImageLoader::ImageLoadedSignalType& ImageLoadedSignal();
+
+  /**
+   * @copydoc Toolkit::AsyncImageLoader::Cancel
+   */
+  bool Cancel( uint32_t loadingTaskId );
+
+  /**
+   * @copydoc Toolkit::AsyncImageLoader::CancelAll
+   */
+  void CancelAll();
+
+  /**
+   * Process the completed loading task from the worker thread.
+   */
+  void ProcessLoadedImage();
+
+protected:
+
+  /**
+   * Destructor
+   */
+  ~AsyncImageLoader();
+
+private:
+
+  Toolkit::AsyncImageLoader::ImageLoadedSignalType mLoadedSignal;
+
+  ImageLoadThread mLoadThread;
+  uint32_t        mLoadTaskId;
+  bool            mIsLoadThreadStarted;
+
+
+};
+
+} // namespace Internal
+
+inline const Internal::AsyncImageLoader& GetImplementation( const Toolkit::AsyncImageLoader& loader )
+{
+  DALI_ASSERT_ALWAYS( loader && "AsyncImageLoader handle is empty" );
+
+  const BaseObject& object = loader.GetBaseObject();
+
+  return static_cast<const Internal::AsyncImageLoader&>( object );
+}
+
+inline Internal::AsyncImageLoader& GetImplementation( Toolkit::AsyncImageLoader& loader )
+{
+  DALI_ASSERT_ALWAYS( loader && "AsyncImageLoader handle is empty" );
+
+  BaseObject& object = loader.GetBaseObject();
+
+  return static_cast<Internal::AsyncImageLoader&>( object );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_ASYNC_IMAGE_LOADER_IMPL_H__ */
@@ -148,24 +148,22 @@ void AtlasPacker::SplitNode( Node* node, SizeType blockWidth, SizeType blockHeig
 
 AtlasPacker::Node* AtlasPacker::SearchNode( Node* node, SizeType packPositionX, SizeType packPositionY, SizeType blockWidth, SizeType blockHeight  )
 {
-  if( node == NULL )
-  {
-    return NULL;
-  }
-
-  if( node->child[0] != NULL) //not a leaf
+  if( node != NULL )
   {
-    Node* newNode = SearchNode(node->child[0], packPositionX, packPositionY, blockWidth, blockHeight);
-    if( newNode == NULL )// try search from the second child.
+    if( node->child[0] != NULL) //not a leaf
     {
-      newNode = SearchNode(node->child[1], packPositionX, packPositionY, blockWidth, blockHeight);
+      Node* newNode = SearchNode(node->child[0], packPositionX, packPositionY, blockWidth, blockHeight);
+      if( newNode == NULL )// try search from the second child.
+      {
+        newNode = SearchNode(node->child[1], packPositionX, packPositionY, blockWidth, blockHeight);
+      }
+      return newNode;
+    }
+    else if( ApproximatelyEqual(node->rectArea.x, packPositionX) && ApproximatelyEqual(node->rectArea.y, packPositionY )
+        && ApproximatelyEqual(node->rectArea.width, blockWidth) && ApproximatelyEqual( node->rectArea.height, blockHeight) )
+    {
+      return node;
     }
-    return newNode;
-  }
-  else if( ApproximatelyEqual(node->rectArea.x, packPositionX) && ApproximatelyEqual(node->rectArea.y, packPositionY )
-           && ApproximatelyEqual(node->rectArea.width, blockWidth) && ApproximatelyEqual( node->rectArea.height, blockHeight) )
-  {
-    return node;
   }
 
   return NULL;
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * 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.
@@ -22,6 +22,7 @@
 #include <string.h>
 #include <dali/public-api/signals/callback.h>
 #include <dali/public-api/images/resource-image.h>
+#include <dali/devel-api/adaptor-framework/bitmap-loader.h>
 #include <dali/integration-api/debug.h>
 
 namespace Dali
@@ -34,45 +35,40 @@ namespace Internal
 {
 
 ImageAtlas::ImageAtlas( SizeType width, SizeType height, Pixel::Format pixelFormat )
-: mPacker( width, height ),
-  mLoadQueue(),
-  mCompleteQueue( new EventThreadCallback( MakeCallback( this, &ImageAtlas::UploadToAtlas ) ) ),
-  mLoadingThread( mLoadQueue, mCompleteQueue ),
+: mAtlas( Texture::New( Dali::TextureType::TEXTURE_2D, pixelFormat, width, height ) ),
+  mPacker( width, height ),
+  mAsyncLoader( Toolkit::AsyncImageLoader::New() ),
   mBrokenImageUrl(""),
   mBrokenImageSize(),
-  mPixelFormat( pixelFormat ),
-  mLoadingThreadStarted( false )
+  mWidth( static_cast<float>(width) ),
+  mHeight( static_cast<float>( height ) ),
+  mPixelFormat( pixelFormat )
 {
-  mAtlas = Atlas::New( width, height, pixelFormat );
-  mWidth = static_cast<float>(width);
-  mHeight = static_cast<float>( height );
+  mAsyncLoader.ImageLoadedSignal().Connect( this, &ImageAtlas::UploadToAtlas );
 }
 
 ImageAtlas::~ImageAtlas()
 {
-  if( mLoadingThreadStarted )
-  {
-    // add an empty task would stop the loading thread from contional wait.
-    mLoadQueue.AddTask( NULL );
-    // stop the loading thread
-    mLoadingThread.Join();
-    // The atlas can still be used as texture after ImageAtlas has been thrown away,
-    // so make sure all the loaded bitmap been uploaded to atlas
-    UploadToAtlas();
-  }
+  mIdRectContainer.Clear();
 }
 
 IntrusivePtr<ImageAtlas> ImageAtlas::New( SizeType width, SizeType height, Pixel::Format pixelFormat )
 {
   IntrusivePtr<ImageAtlas> internal = new ImageAtlas( width, height, pixelFormat );
+
   return internal;
 }
 
-Image ImageAtlas::GetAtlas()
+Texture ImageAtlas::GetAtlas()
 {
   return mAtlas;
 }
 
+float ImageAtlas::GetOccupancyRate() const
+{
+  return 1.f - static_cast<float>( mPacker.GetAvailableArea() ) / ( mWidth*mHeight );
+}
+
 void ImageAtlas::SetBrokenImage( const std::string& brokenImageUrl )
 {
   mBrokenImageSize = ResourceImage::GetImageSize( brokenImageUrl );
@@ -107,24 +103,12 @@ bool ImageAtlas::Upload( Vector4& textureRect,
     }
   }
 
-  if( static_cast<unsigned int>(dimensions.GetWidth() * dimensions.GetHeight()) > mPacker.GetAvailableArea() )
-  {
-    return false;
-  }
-
   unsigned int packPositionX = 0;
   unsigned int packPositionY = 0;
   if( mPacker.Pack( dimensions.GetWidth(), dimensions.GetHeight(), packPositionX, packPositionY ) )
   {
-    if( !mLoadingThreadStarted )
-    {
-      mLoadingThread.Start();
-      mLoadingThreadStarted = true;
-    }
-
-    LoadingTask* newTask = new LoadingTask(BitmapLoader::New(url, size, fittingMode, SamplingMode::BOX_THEN_LINEAR, orientationCorrection ),
-                                           packPositionX, packPositionY, dimensions.GetWidth(), dimensions.GetHeight());
-    mLoadQueue.AddTask( newTask );
+    unsigned short loadId = mAsyncLoader.Load( url, size, fittingMode, SamplingMode::BOX_THEN_LINEAR, orientationCorrection );
+    mIdRectContainer.PushBack( new IdRectPair( loadId, packPositionX, packPositionY, dimensions.GetWidth(), dimensions.GetHeight() ) );
 
     // apply the half pixel correction
     textureRect.x = ( static_cast<float>( packPositionX ) +0.5f ) / mWidth; // left
@@ -144,7 +128,7 @@ bool ImageAtlas::Upload( Vector4& textureRect, PixelData pixelData )
   unsigned int packPositionY = 0;
   if( mPacker.Pack( pixelData.GetWidth(), pixelData.GetHeight(), packPositionX, packPositionY ) )
   {
-    mAtlas.Upload( pixelData, packPositionX, packPositionY );
+    mAtlas.Upload( pixelData, 0u, 0u, packPositionX, packPositionY, pixelData.GetWidth(), pixelData.GetHeight() );
 
     // apply the half pixel correction
     textureRect.x = ( static_cast<float>( packPositionX ) +0.5f ) / mWidth; // left
@@ -166,38 +150,36 @@ void ImageAtlas::Remove( const Vector4& textureRect )
                        static_cast<SizeType>((textureRect.w-textureRect.y)*mHeight+1.f) );
 }
 
-void ImageAtlas::UploadToAtlas()
+void ImageAtlas::UploadToAtlas( unsigned int id, PixelData pixelData )
 {
-  while( LoadingTask* next = mCompleteQueue.NextTask() )
+  if(  mIdRectContainer[0]->loadTaskId == id)
   {
-    if( ! next->loader.IsLoaded() )
+    if( !pixelData || ( pixelData.GetWidth() ==0 && pixelData.GetHeight() == 0 ))
     {
       if(!mBrokenImageUrl.empty()) // replace with the broken image
       {
-        UploadBrokenImage( next->packRect );
+        UploadBrokenImage( mIdRectContainer[0]->packRect );
       }
-
-      DALI_LOG_ERROR( "Failed to load the image: %s\n", (next->loader.GetUrl()).c_str());
     }
     else
     {
-      if( next->loader.GetPixelData().GetWidth() < next->packRect.width || next->loader.GetPixelData().GetHeight() < next->packRect.height  )
+      if( pixelData.GetWidth() < mIdRectContainer[0]->packRect.width || pixelData.GetHeight() < mIdRectContainer[0]->packRect.height  )
       {
         DALI_LOG_ERROR( "Can not upscale the image from actual loaded size [ %d, %d ] to specified size [ %d, %d ]\n",
-                        next->loader.GetPixelData().GetWidth(),
-                        next->loader.GetPixelData().GetHeight(),
-                        next->packRect.width,
-                        next->packRect.height );
+                        pixelData.GetWidth(), pixelData.GetHeight(),
+                        mIdRectContainer[0]->packRect.width,  mIdRectContainer[0]->packRect.height );
       }
 
-      mAtlas.Upload( next->loader.GetPixelData(), next->packRect.x, next->packRect.y );
+      mAtlas.Upload( pixelData, 0u, 0u,
+                    mIdRectContainer[0]->packRect.x, mIdRectContainer[0]->packRect.y,
+                    mIdRectContainer[0]->packRect.width, mIdRectContainer[0]->packRect.height );
     }
-
-    delete next;
   }
+
+  mIdRectContainer.Erase( mIdRectContainer.Begin() );
 }
 
-void ImageAtlas::UploadBrokenImage( const Rect<SizeType>& area )
+void ImageAtlas::UploadBrokenImage( const Rect<unsigned int>& area )
 {
   BitmapLoader loader = BitmapLoader::New(mBrokenImageUrl, ImageDimensions( area.width, area.height ) );
   loader.Load();
@@ -228,10 +210,10 @@ void ImageAtlas::UploadBrokenImage( const Rect<SizeType>& area )
     {
       buffer[idx] = 0x00;
     }
-    mAtlas.Upload( background, area.x, area.y );
+    mAtlas.Upload( background, 0u, 0u, area.x, area.y, area.width, area.height );
   }
 
-  mAtlas.Upload( loader.GetPixelData(), packX, packY );
+  mAtlas.Upload( loader.GetPixelData(), 0u, 0u, packX, packY, loadedWidth, loadedHeight );
 }
 
 } // namespace Internal
 // EXTERNAL INCLUDES
 #include <dali/public-api/common/intrusive-ptr.h>
 #include <dali/public-api/object/base-object.h>
+#include <dali/public-api/signals/connection-tracker.h>
+#include <dali/devel-api/common/owner-container.h>
 #include <dali/devel-api/images/atlas.h>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/image-atlas/image-atlas.h>
-#include <dali-toolkit/internal/image-atlas/atlas-packer.h>
-#include <dali-toolkit/internal/image-atlas/image-load-thread.h>
+#include <dali-toolkit/devel-api/image-loader/image-atlas.h>
+#include <dali-toolkit/devel-api/image-loader/async-image-loader.h>
+#include <dali-toolkit/internal/image-loader/atlas-packer.h>
 
 namespace Dali
 {
@@ -37,7 +39,7 @@ namespace Toolkit
 namespace Internal
 {
 
-class ImageAtlas : public BaseObject
+class ImageAtlas : public BaseObject, public ConnectionTracker
 {
 public:
 
@@ -59,7 +61,12 @@ public:
   /**
    * @copydoc Toolkit::ImageAtlas::GetAtlas
    */
-  Image GetAtlas();
+  Texture GetAtlas();
+
+  /**
+   * @copydoc Toolkit::ImageAtlas::GetOccupancyRate
+   */
+  float GetOccupancyRate() const;
 
   /**
    * @copydoc Toolkit::ImageAtlas::SetBrokenImage
@@ -95,16 +102,16 @@ protected:
 private:
 
   /**
-   * Upload the bitmap to atlas when the image is loaded in the worker thread.
+   * @copydoc PixelDataRequester::ProcessPixels
    */
-  void UploadToAtlas();
+  void UploadToAtlas( unsigned int id, PixelData pixelData );
 
   /**
    * Upload broken image
    *
    * @param[in] area The pixel area for uploading.
    */
-  void UploadBrokenImage( const Rect<SizeType>& area );
+  void UploadBrokenImage( const Rect<unsigned int>& area );
 
   // Undefined
   ImageAtlas( const ImageAtlas& imageAtlas);
@@ -114,19 +121,31 @@ private:
 
 private:
 
-  Atlas                mAtlas;
-  AtlasPacker          mPacker;
-
-  LoadQueue            mLoadQueue;
-  CompleteQueue        mCompleteQueue;
-  ImageLoadThread      mLoadingThread;
-
-  std::string          mBrokenImageUrl;
-  ImageDimensions      mBrokenImageSize;
-  float                mWidth;
-  float                mHeight;
-  Pixel::Format        mPixelFormat;
-  bool                 mLoadingThreadStarted;
+  struct IdRectPair
+  {
+    IdRectPair( unsigned short loadTaskId,
+                unsigned int packPositionX,
+                unsigned int packPositionY,
+                unsigned int width,
+                unsigned int height )
+    : loadTaskId( loadTaskId ),
+      packRect( packPositionX, packPositionY, width, height )
+    {}
+
+    unsigned short loadTaskId;
+    Rect<unsigned int> packRect;
+  };
+
+  OwnerContainer<IdRectPair*> mIdRectContainer;
+
+  Texture                   mAtlas;
+  AtlasPacker               mPacker;
+  Toolkit::AsyncImageLoader mAsyncLoader;
+  std::string               mBrokenImageUrl;
+  ImageDimensions           mBrokenImageSize;
+  float                     mWidth;
+  float                     mHeight;
+  Pixel::Format             mPixelFormat;
 
 };
 
@@ -27,46 +27,45 @@ namespace Toolkit
 namespace Internal
 {
 
-LoadingTask::LoadingTask(BitmapLoader loader, uint32_t packPositionX, uint32_t packPositionY, uint32_t width, uint32_t height )
+LoadingTask::LoadingTask(uint32_t id, BitmapLoader loader )
 : loader( loader ),
-  packRect( packPositionX, packPositionY, width, height )
+  id( id )
 {
 }
 
-LoadQueue::LoadQueue()
+ImageLoadThread::ImageLoadThread( EventThreadCallback* trigger )
+: mTrigger( trigger )
 {
 }
 
-LoadQueue::~LoadQueue()
+ImageLoadThread::~ImageLoadThread()
 {
+  // add an empty task would stop the thread from conditional wait.
+  AddTask( NULL );
+  // stop the thread
+  Join();
+
+  delete mTrigger;
 }
 
-LoadingTask* LoadQueue::NextTask()
+void ImageLoadThread::Run()
 {
-  // Lock while popping task out from the queue
-  ConditionalWait::ScopedLock lock( mConditionalWait );
-
-  while( mTasks.Empty() )
+  while( LoadingTask* task =  NextTaskToProcess())
   {
-    mConditionalWait.Wait( lock );
+    task->loader.Load();
+    AddCompletedTask( task );
   }
-
-  Vector< LoadingTask* >::Iterator next = mTasks.Begin();
-  LoadingTask* nextTask = *next;
-  mTasks.Erase( next );
-
-  return nextTask;
 }
 
-void LoadQueue::AddTask( LoadingTask* task )
+void ImageLoadThread::AddTask( LoadingTask* task )
 {
   bool wasEmpty = false;
 
   {
     // Lock while adding task to the queue
     ConditionalWait::ScopedLock lock( mConditionalWait );
-    wasEmpty = mTasks.Empty();
-    mTasks.PushBack( task );
+    wasEmpty = mLoadQueue.Empty();
+    mLoadQueue.PushBack( task );
   }
 
   if( wasEmpty)
@@ -76,62 +75,83 @@ void LoadQueue::AddTask( LoadingTask* task )
   }
 }
 
-CompleteQueue::CompleteQueue(EventThreadCallback* trigger)
-: mTrigger( trigger )
-{}
-
-CompleteQueue::~CompleteQueue()
-{
-  delete mTrigger;
-}
-
-LoadingTask* CompleteQueue::NextTask()
+LoadingTask* ImageLoadThread::NextCompletedTask()
 {
   // Lock while popping task out from the queue
   Mutex::ScopedLock lock( mMutex );
 
-  if( mTasks.Empty() )
+  if( mCompleteQueue.Empty() )
   {
     return NULL;
   }
 
-  Vector< LoadingTask* >::Iterator next = mTasks.Begin();
+  Vector< LoadingTask* >::Iterator next = mCompleteQueue.Begin();
   LoadingTask* nextTask = *next;
-  mTasks.Erase( next );
+  mCompleteQueue.Erase( next );
 
   return nextTask;
 }
 
-void CompleteQueue::AddTask( LoadingTask* task )
+bool ImageLoadThread::CancelTask( uint32_t loadingTaskId )
 {
-  // Lock while adding task to the queue
-  Mutex::ScopedLock lock( mMutex );
-  mTasks.PushBack( task );
+  // Lock while remove task from the queue
+  ConditionalWait::ScopedLock lock( mConditionalWait );
 
-  // wake up the main thread
-  mTrigger->Trigger();
+  for( Vector< LoadingTask* >::Iterator iter = mLoadQueue.Begin(); iter != mLoadQueue.End(); iter++ )
+  {
+    if( (*iter)->id == loadingTaskId )
+    {
+      delete (*iter);
+      mLoadQueue.Erase( iter );
+      return true;
+    }
+  }
+
+  return false;
 }
 
 
-ImageLoadThread::ImageLoadThread( LoadQueue& loadQueue, CompleteQueue& completeQueue )
-: mLoadQueue( loadQueue ),
-  mCompleteQueue( completeQueue )
+void ImageLoadThread::CancelAll()
 {
-}
+  // Lock while remove task from the queue
+  ConditionalWait::ScopedLock lock( mConditionalWait );
 
-ImageLoadThread::~ImageLoadThread()
-{
+  for( Vector< LoadingTask* >::Iterator iter = mLoadQueue.Begin(); iter != mLoadQueue.End(); iter++ )
+  {
+    delete (*iter);
+  }
+  mLoadQueue.Clear();
 }
 
-void ImageLoadThread::Run()
+LoadingTask* ImageLoadThread::NextTaskToProcess()
 {
-  while( LoadingTask* task = mLoadQueue.NextTask() )
+  // Lock while popping task out from the queue
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+
+  while( mLoadQueue.Empty() )
   {
-    task->loader.Load();
-    mCompleteQueue.AddTask( task );
+    mConditionalWait.Wait( lock );
   }
+
+  Vector< LoadingTask* >::Iterator next = mLoadQueue.Begin();
+  LoadingTask* nextTask = *next;
+  mLoadQueue.Erase( next );
+
+  return nextTask;
 }
 
+void ImageLoadThread::AddCompletedTask( LoadingTask* task )
+{
+  // Lock while adding task to the queue
+  Mutex::ScopedLock lock( mMutex );
+  mCompleteQueue.PushBack( task );
+
+  // wake up the main thread
+  mTrigger->Trigger();
+}
+
+
+
 } // namespace Internal
 
 } // namespace Toolkit
@@ -43,7 +43,7 @@ struct LoadingTask
   /**
    * Constructor.
    */
-  LoadingTask( BitmapLoader loader, uint32_t packPositionX, uint32_t packPositionY, uint32_t width, uint32_t height  );
+  LoadingTask( uint32_t id, BitmapLoader loader );
 
 private:
 
@@ -55,123 +55,69 @@ private:
 
 public:
 
-  BitmapLoader   loader;    ///< The loader used to load the bitmap from URL
-  Rect<uint32_t> packRect;  ///< The x coordinate of the position to pack the image.
-
+  BitmapLoader loader;    ///< The loader used to load the bitmap from URL
+  uint32_t     id;        ///< The id associated with this task.
 };
 
+
 /**
- * The queue of the tasks waiting to load the bitmap from the URL in the worker thread/
+ * The worker thread for image loading.
  */
-class LoadQueue //: public TaskQueue
+class ImageLoadThread : public Thread
 {
 public:
 
   /**
-   * Constructor
+   * Constructor.
+   *
+   * @param[in] mTrigger The trigger to wake up the main thread.
    */
-  LoadQueue();
+  ImageLoadThread( EventThreadCallback* mTrigger );
 
   /**
    * Destructor.
    */
-  ~LoadQueue();
-
-  /**
-   * Pop the next task out from the queue.
-   *
-   * @return The next task to be processed.
-   */
-  LoadingTask* NextTask();
+  virtual ~ImageLoadThread();
 
   /**
-   * Add a task in to the queue
+   * Add a task in to the loading queue
    *
    * @param[in] task The task added to the queue.
    */
   void AddTask( LoadingTask* task );
 
-private:
-
-  // Undefined
-  LoadQueue( const LoadQueue& queue );
-
-  // Undefined
-  LoadQueue& operator=( const LoadQueue& queue );
-
-private:
-
-  Vector< LoadingTask* > mTasks;
-  ConditionalWait mConditionalWait;
-};
-
-/**
- * The queue of the tasks, with the image loaded, waiting for the main thread to upload the bitmap.
- */
-class CompleteQueue //: public TaskQueue
-{
-public:
-
   /**
-   * Constructor
+   * Pop the next task out from the completed queue.
    *
-   * @param[in] mTrigger The trigger to wake up the main thread.
-   */
-  CompleteQueue( EventThreadCallback* mTrigger );
-
-  /**
-   * Destructor.
+   * @return The next task to be processed.
    */
-  ~CompleteQueue();
+  LoadingTask* NextCompletedTask();
 
   /**
-   * Pop the next task out from the queue.
-   *
-   * @return The next task to be processed.
+   * Remove the loading task from the waiting queue.
    */
-  LoadingTask* NextTask();
+  bool CancelTask( uint32_t loadingTaskId );
 
   /**
-   * Add a task in to the queue
-   *
-   * @param[in] task The task added to the queue.
+   * Remove all the loading tasks in the waiting queue.
    */
-  void AddTask( LoadingTask* task );
-
-private:
-
-  // Undefined
-  CompleteQueue( const CompleteQueue& queue );
-
-  // Undefined
-  CompleteQueue& operator=( const CompleteQueue& queue );
+  void CancelAll();
 
 private:
 
-  Vector< LoadingTask* > mTasks;
-  Dali::Mutex            mMutex;
-  EventThreadCallback*   mTrigger;
-};
-
-/**
- * The worker thread for image loading.
- */
-class ImageLoadThread : public Thread
-{
-public:
-
   /**
-   * Constructor.
+   * Pop the next loading task out from the queue to process.
    *
-   * @param[in] loadQueue The task queue with images for loading.
-   * @param[in] completeQurue The task queue with images loaded.
+   * @return The next task to be processed.
    */
-  ImageLoadThread( LoadQueue& loadQueue, CompleteQueue& completeQueue );
+  LoadingTask* NextTaskToProcess();
 
   /**
-   * Destructor.
+   * Add a task in to the loading queue
+   *
+   * @param[in] task The task added to the queue.
    */
-  virtual ~ImageLoadThread();
+  void AddCompletedTask( LoadingTask* task );
 
 protected:
 
@@ -191,8 +137,12 @@ private:
 
 private:
 
-  LoadQueue& mLoadQueue;          ///<The task queue with images for loading.
-  CompleteQueue& mCompleteQueue;  ///<The task queue with images loaded.
+  Vector< LoadingTask* > mLoadQueue;     ///<The task queue with images for loading.
+  Vector< LoadingTask* > mCompleteQueue; ///<The task queue with images loaded.
+
+  ConditionalWait        mConditionalWait;
+  Dali::Mutex            mMutex;
+  EventThreadCallback*   mTrigger;
 };
 
 } // namespace Internal
index 9697e50..66897e4 100644 (file)
@@ -142,7 +142,7 @@ void ImageAtlasManager::CreateNewAtlas()
   }
   mAtlasList.push_back( newAtlas );
   TextureSet textureSet = TextureSet::New();
-  TextureSetImage( textureSet, 0u, newAtlas.GetAtlas() );
+  textureSet.SetTexture( 0u, newAtlas.GetAtlas() );
   mTextureSetList.push_back( textureSet );
 }
 
index 6553ed9..4586236 100644 (file)
@@ -24,7 +24,7 @@
 #include <dali/public-api/rendering/texture-set.h>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/image-atlas/image-atlas.h>
+#include <dali-toolkit/devel-api/image-loader/image-atlas.h>
 
 namespace Dali
 {