[3.0] Published the AsyncImageLoader and SyncImageLoader to the public API 34/98534/2
authorTom Robinson <tom.robinson@samsung.com>
Thu, 17 Nov 2016 12:53:25 +0000 (12:53 +0000)
committerTom Robinson <tom.robinson@samsung.com>
Thu, 17 Nov 2016 14:13:34 +0000 (14:13 +0000)
Change-Id: Ia9b7131fab371e3f1a263036710ca4a26747a8f8

46 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
automated-tests/src/dali-toolkit/utc-Dali-PageTurnView.cpp
automated-tests/src/dali-toolkit/utc-Dali-SyncImageLoader.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp
automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp
build/tizen/dali-toolkit/Makefile.am
build/tizen/docs/dali.doxy.in
dali-toolkit/dali-toolkit.h
dali-toolkit/devel-api/controls/page-turn-view/page-factory.h
dali-toolkit/devel-api/file.list
dali-toolkit/devel-api/image-loader/atlas-upload-observer.cpp [new file with mode: 0644]
dali-toolkit/devel-api/image-loader/atlas-upload-observer.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 76% similarity]
dali-toolkit/devel-api/image-loader/image-atlas.h [moved from dali-toolkit/devel-api/image-atlas/image-atlas.h with 65% similarity]
dali-toolkit/internal/controls/page-turn-view/page-turn-view-impl.cpp
dali-toolkit/internal/controls/page-turn-view/page-turn-view-impl.h
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 59% similarity]
dali-toolkit/internal/image-loader/image-atlas-impl.h [moved from dali-toolkit/internal/image-atlas/image-atlas-impl.h with 59% similarity]
dali-toolkit/internal/image-loader/image-load-thread.cpp [moved from dali-toolkit/internal/image-atlas/image-load-thread.cpp with 51% 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
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/image/image-visual.h
dali-toolkit/internal/visuals/npatch/npatch-visual.cpp
dali-toolkit/internal/visuals/svg/svg-visual.cpp
dali-toolkit/internal/visuals/svg/svg-visual.h
dali-toolkit/internal/visuals/visual-base-data-impl.h
dali-toolkit/internal/visuals/visual-factory-cache.cpp
dali-toolkit/internal/visuals/visual-factory-cache.h
dali-toolkit/internal/visuals/visual-factory-impl.cpp
dali-toolkit/internal/visuals/visual-factory-impl.h
dali-toolkit/public-api/file.list
dali-toolkit/public-api/image-loader/async-image-loader.cpp [new file with mode: 0644]
dali-toolkit/public-api/image-loader/async-image-loader.h [new file with mode: 0644]
dali-toolkit/public-api/image-loader/sync-image-loader.cpp [new file with mode: 0644]
dali-toolkit/public-api/image-loader/sync-image-loader.h [new file with mode: 0644]
dali-toolkit/public-api/visuals/image-visual-properties.h

index c3723e0..8fe704d 100644 (file)
@@ -53,6 +53,8 @@ SET(TC_SOURCES
    utc-Dali-DebugRendering.cpp
    utc-Dali-ImageAtlas.cpp
    utc-Dali-VideoView.cpp
+   utc-Dali-AsyncImageLoader.cpp
+   utc-Dali-SyncImageLoader.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..74dcc73
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * 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/dali-toolkit.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 UtcDaliAsyncImageLoaderDownCastP(void)
+{
+  AsyncImageLoader asyncImageLoader = AsyncImageLoader::New();
+  BaseHandle object(asyncImageLoader);
+
+  AsyncImageLoader asyncImageLoader2 = AsyncImageLoader::DownCast( object );
+
+  DALI_TEST_CHECK( asyncImageLoader2 );
+
+  END_TEST;
+}
+
+int UtcDaliAsyncImageLoaderDownCastN(void)
+{
+  BaseHandle unInitializedObject;
+  AsyncImageLoader asyncImageLoader = AsyncImageLoader::DownCast( unInitializedObject );
+
+  DALI_TEST_CHECK( !asyncImageLoader );
+
+  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;
+}
+
+// Note: This is not an ideal test, but we cannot guarantee we can call Cancel() before the image has finished loading.
+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 );
+
+  EventThreadCallback* eventTrigger = EventThreadCallback::Get();
+  CallbackBase* callback = eventTrigger->GetCallback();
+
+  eventTrigger->WaitingForTrigger( 3 ); // waiting until images are loaded
+
+  CallbackBase::Execute( *callback );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( loadedSignalVerifier.LoadedImageCount() == 3 );
+
+  DALI_TEST_CHECK( !loader.Cancel( id03 ) ); // Cannot cancel a task that is already implemeted
+
+  DALI_TEST_CHECK( loadedSignalVerifier.Verify( id01, 34, 34 ) );   // first image is loaded
+  DALI_TEST_CHECK( loadedSignalVerifier.Verify( id02, 25, 25 ) );   // second image is loaded
+  DALI_TEST_CHECK( loadedSignalVerifier.Verify( id03, 100, 100 ) ); // third image is loaded
+
+  END_TEST;
+}
+
+int UtcDaliAsyncImageLoaderCancelAll(void)
+{
+  ToolkitTestApplication application;
+
+  AsyncImageLoader loader = AsyncImageLoader::New();
+
+  // Test that it is safe to call CancelAll even there is no loading task requested.
+  try
+  {
+    loader.CancelAll();
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "AsyncImageLoader::LoadAll", TEST_LOCATION);
+  }
+
+  // Test that cancelling a non-existing loading task will return false
+  uint32_t id = 1;
+  DALI_TEST_CHECK( !(loader.Cancel( id )) );
+
+  END_TEST;
+}
+
index a8fa8cc..5fe744f 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;
@@ -61,6 +60,22 @@ bool IsOverlap( Rect<int> rect1, Rect<int> rect2 )
      && rect2.y < rect1.y+rect1.height;
 }
 
+static unsigned int gCountOfTestFuncCall;
+class TestUploadObserver : public AtlasUploadObserver
+{
+public:
+  TestUploadObserver()
+  {}
+
+  virtual ~TestUploadObserver()
+  {}
+
+  void UploadCompleted()
+  {
+    gCountOfTestFuncCall++;
+  }
+};
+
 } // anonymous namespace
 
 void dali_image_atlas_startup(void)
@@ -120,15 +135,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 +196,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 +207,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 );
@@ -226,6 +257,100 @@ int UtcDaliImageAtlasUploadP(void)
   END_TEST;
 }
 
+int UtcDaliImageAtlasUploadWithObserver01(void)
+{
+  TestApplication application;
+  ImageAtlas atlas = ImageAtlas::New( 200, 200 );
+
+  EventThreadCallback* eventTrigger = EventThreadCallback::Get();
+  CallbackBase* callback = eventTrigger->GetCallback();
+
+  gCountOfTestFuncCall = 0;
+  TestUploadObserver uploadObserver;
+
+  Vector4 textureRect1;
+  atlas.Upload( textureRect1, gImage_34_RGBA, ImageDimensions(34, 34), FittingMode::DEFAULT, true, &uploadObserver );
+  Vector4 textureRect2;
+  atlas.Upload( textureRect2, gImage_50_RGBA, ImageDimensions(50, 50), FittingMode::DEFAULT, true, NULL );
+  Vector4 textureRect3;
+  atlas.Upload( textureRect3, gImage_128_RGB, ImageDimensions(128, 128), FittingMode::DEFAULT, true, &uploadObserver );
+
+  // waiting until all three images are loaded and uploaded to atlas
+  eventTrigger->WaitingForTrigger( 3 );
+  CallbackBase::Execute( *callback );
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+
+  // Check that TestFunc is called twice
+  DALI_TEST_EQUALS( gCountOfTestFuncCall, 2, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageAtlasUploadWithObserver02(void)
+{
+  TestApplication application;
+  ImageAtlas atlas = ImageAtlas::New( 200, 200 );
+
+  EventThreadCallback* eventTrigger = EventThreadCallback::Get();
+  CallbackBase* callback = eventTrigger->GetCallback();
+
+  gCountOfTestFuncCall = 0;
+  TestUploadObserver* uploadObserver = new TestUploadObserver;
+
+  Vector4 textureRect1;
+  atlas.Upload( textureRect1, gImage_34_RGBA, ImageDimensions(34, 34), FittingMode::DEFAULT, true, uploadObserver );
+  Vector4 textureRect2;
+  atlas.Upload( textureRect2, gImage_50_RGBA, ImageDimensions(50, 50), FittingMode::DEFAULT, true, uploadObserver );
+  Vector4 textureRect3;
+  atlas.Upload( textureRect3, gImage_128_RGB, ImageDimensions(128, 128), FittingMode::DEFAULT, true, uploadObserver );
+
+  // destroy the object.
+  delete uploadObserver;
+
+ // waiting until all three images are loaded and uploaded to atlas
+  eventTrigger->WaitingForTrigger( 3 );
+  CallbackBase::Execute( *callback );
+  application.Render(RENDER_FRAME_INTERVAL);
+  application.SendNotification();
+
+  // Check that TestFunc is called twice
+  DALI_TEST_EQUALS( gCountOfTestFuncCall, 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageAtlasUploadWithObserver03(void)
+{
+  TestApplication application;
+
+  gCountOfTestFuncCall = 0;
+  TestUploadObserver* uploadObserver = new TestUploadObserver;
+
+  {
+    ImageAtlas atlas = ImageAtlas::New( 200, 200 );
+
+    Vector4 textureRect1;
+    atlas.Upload( textureRect1, gImage_34_RGBA, ImageDimensions(34, 34), FittingMode::DEFAULT, true, uploadObserver );
+    Vector4 textureRect2;
+    atlas.Upload( textureRect2, gImage_50_RGBA, ImageDimensions(50, 50), FittingMode::DEFAULT, true, uploadObserver );
+    Vector4 textureRect3;
+    atlas.Upload( textureRect3, gImage_128_RGB, ImageDimensions(128, 128), FittingMode::DEFAULT, true, uploadObserver );
+  }
+
+  //ImageAtlas is out of scope, so it will get destroyed
+
+  application.Render(RENDER_FRAME_INTERVAL);
+  application.SendNotification();
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+
+  // Check that TestFunc is called twice
+  DALI_TEST_EQUALS( gCountOfTestFuncCall, 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
 int UtcDaliImageAtlasRemove(void)
 {
   TestApplication application;
index 424e79d..12c3f17 100644 (file)
@@ -393,6 +393,7 @@ int UtcDaliImageViewAsyncLoadingWithAltasing(void)
   callStack.Reset();
   callStack.Enable(true);
 
+  BitmapLoader::ResetLatestCreated();
   ImageView imageView = ImageView::New( gImage_34_RGBA, ImageDimensions( 34, 34 ) );
 
   // By default, Aysnc loading is used
@@ -417,6 +418,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 ab4551f..85ba766 100644 (file)
@@ -21,7 +21,6 @@
 #include <sstream>
 #include <dali-toolkit-test-suite-utils.h>
 #include <dali/integration-api/events/pan-gesture-event.h>
-#include <dali/public-api/images/buffer-image.h>
 #include <dali-toolkit/devel-api/controls/page-turn-view/page-factory.h>
 #include <dali-toolkit/devel-api/controls/page-turn-view/page-turn-landscape-view.h>
 #include <dali-toolkit/devel-api/controls/page-turn-view/page-turn-portrait-view.h>
@@ -35,9 +34,6 @@ namespace
 const int RENDER_FRAME_INTERVAL = 16;                           ///< Duration of each frame in ms. (at approx 60FPS)
 const unsigned int TOTAL_PAGE_NUMBER = 20;
 const Vector2 PAGE_SIZE( 300.f,400.f );
-const unsigned int IMAGE_WIDTH = 30;
-const unsigned int IMAGE_HEIGHT = 30;
-const Vector2 IMAGE_SIZE( static_cast<float>( IMAGE_WIDTH ), static_cast<float>(IMAGE_HEIGHT) );
 const Vector2 SPINE_SHADOW_PARAMETER( 60.0f, 30.0f );
 
 static bool gObjectCreatedCallBackCalled;
@@ -189,8 +185,9 @@ class TestPageFactory : public PageFactory
 {
 public:
 
-  TestPageFactory(ToolkitTestApplication& application)
-  : mApplication( application )
+  TestPageFactory(ToolkitTestApplication& application, bool returnValidTexture = true )
+  : mApplication( application ),
+    mValidTexture( returnValidTexture )
   {
     mTotalPageNumber = TOTAL_PAGE_NUMBER;
   }
@@ -205,18 +202,23 @@ public:
   }
 
   /**
-   * Create an image to represent a page content.
+   * Create an texture to represent a page content.
    * @param[in] pageId The ID of the page to create.
    * @return An image, or an empty handle if the ID is out of range.
    */
-  virtual Image NewPage( unsigned int pageId )
+  virtual Texture NewPage( unsigned int pageId )
   {
-    return BufferImage::WHITE();
+    if( mValidTexture )
+    {
+      return Texture::New( Dali::TextureType::TEXTURE_2D, Pixel::RGB888, 100, 100 );
+    }
+    return Texture(); // empty handle
   }
 
 private:
   ToolkitTestApplication& mApplication;
   unsigned int            mTotalPageNumber;
+  bool                    mValidTexture;
 };
 
 }// namespace
@@ -689,3 +691,34 @@ int UtcDaliPageImageFactoryGetExtention(void)
   DALI_TEST_CHECK( factory.GetExtension() == NULL );
   END_TEST;
 }
+
+int UtcDaliPageTurnEmptyTextureHandle(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliPageTurnEmptyTextureHandle ");
+
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE );
+
+  TestPageFactory factory(application, false); // returns empty handles
+  Vector2 size = Stage::GetCurrent().GetSize();
+  try
+  {
+    PageTurnView portraitView = PageTurnPortraitView::New( factory, size );
+    portraitView.SetParentOrigin( ParentOrigin::CENTER );
+    Stage::GetCurrent().Add( portraitView );
+
+    tet_result(TET_FAIL);
+  }
+  catch (DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "must pass in valid texture", TEST_LOCATION );
+  }
+  catch (...)
+  {
+    tet_result(TET_FAIL);
+  }
+
+  END_TEST;
+}
+
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-SyncImageLoader.cpp b/automated-tests/src/dali-toolkit/utc-Dali-SyncImageLoader.cpp
new file mode 100644 (file)
index 0000000..d37c5fc
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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 <dali-toolkit/dali-toolkit.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+
+// 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";
+
+
+void VerifyLoad( PixelData pixelData, uint32_t width, uint32_t height )
+{
+  DALI_TEST_CHECK( pixelData );
+  DALI_TEST_EQUALS<unsigned int>( pixelData.GetWidth(), width, TEST_LOCATION );
+  DALI_TEST_EQUALS<unsigned int>( pixelData.GetHeight(), height, TEST_LOCATION );
+}
+
+} // anonymous namespace
+
+
+int UtcDaliSyncImageLoaderLoad(void)
+{
+  PixelData pixelData = Toolkit::SyncImageLoader::Load( gImage_50_RGBA );
+
+  DALI_TEST_EQUALS<bool>( pixelData, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliSyncImageLoaderLoadWithDimensions(void)
+{
+  PixelData pixelData = Toolkit::SyncImageLoader::Load( gImage_50_RGBA, ImageDimensions( 25, 25 ) );
+
+  VerifyLoad( pixelData, 25u, 25u );
+
+  END_TEST;
+}
+
+int UtcDaliSyncImageLoaderLoadWithAllOptions(void)
+{
+  PixelData pixelData = Toolkit::SyncImageLoader::Load( gImage_128_RGB, ImageDimensions( 100, 100 ), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, true );
+
+  VerifyLoad( pixelData, 100u, 100u );
+
+  END_TEST;
+}
+
+
index b4e4461..d82277d 100644 (file)
@@ -500,6 +500,9 @@ int UtcDaliVisualGetPropertyMap5(void)
   propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT,   30 );
   propertyMap.Insert( ImageVisual::Property::FITTING_MODE,   FittingMode::FIT_HEIGHT );
   propertyMap.Insert( ImageVisual::Property::SAMPLING_MODE,   SamplingMode::BOX_THEN_NEAREST );
+  propertyMap.Insert( ImageVisual::Property::PIXEL_AREA, Vector4( 0.25f, 0.25f, 0.5f, 0.5f ) );
+  propertyMap.Insert( ImageVisual::Property::WRAP_MODE_U, WrapMode::REPEAT );
+  propertyMap.Insert( ImageVisual::Property::WRAP_MODE_V, WrapMode::MIRRORED_REPEAT );
   propertyMap.Insert( "synchronousLoading",   true );
 
   Visual::Base imageVisual = factory.CreateVisual(propertyMap);
@@ -533,6 +536,18 @@ int UtcDaliVisualGetPropertyMap5(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<int>() == 30 );
 
+  value = resultMap.Find( ImageVisual::Property::PIXEL_AREA, Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), Vector4( 0.25f, 0.25f, 0.5f, 0.5f ), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( ImageVisual::Property::WRAP_MODE_U, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK(  value->Get<int>() == WrapMode::REPEAT);
+
+  value = resultMap.Find( ImageVisual::Property::WRAP_MODE_V, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK(  value->Get<int>() == WrapMode::MIRRORED_REPEAT);
+
   value = resultMap.Find( "synchronousLoading",   Property::BOOLEAN );
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<bool>() == true );
@@ -566,6 +581,18 @@ int UtcDaliVisualGetPropertyMap5(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<int>() == 200 );
 
+  value = resultMap.Find( ImageVisual::Property::PIXEL_AREA, Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), Vector4( 0.f, 0.f, 1.f, 1.f ), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( ImageVisual::Property::WRAP_MODE_U, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK(  value->Get<int>() == WrapMode::DEFAULT);
+
+  value = resultMap.Find( ImageVisual::Property::WRAP_MODE_V, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK(  value->Get<int>() == WrapMode::DEFAULT);
+
   value = resultMap.Find( "synchronousLoading",   Property::BOOLEAN );
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<bool>() == false );
index 15058d9..d1e2787 100644 (file)
@@ -17,6 +17,7 @@
 #include <iostream>
 #include <stdlib.h>
 #include <dali-toolkit-test-suite-utils.h>
+#include <toolkit-bitmap-loader.h>
 #include <toolkit-event-thread-callback.h>
 #include <dali/public-api/rendering/renderer.h>
 #include <dali/public-api/rendering/texture-set.h>
@@ -34,13 +35,17 @@ typedef NinePatchImage::StretchRanges StretchRanges;
 
 const char* TEST_IMAGE_FILE_NAME =  "gallery_image_01.jpg";
 const char* TEST_NPATCH_FILE_NAME =  "gallery_image_01.9.png";
-
 const char* TEST_SVG_FILE_NAME = TEST_RESOURCE_DIR "/svg1.svg";
 const char* TEST_OBJ_FILE_NAME = TEST_RESOURCE_DIR "/Cube.obj";
 const char* TEST_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal.mtl";
 const char* TEST_SIMPLE_OBJ_FILE_NAME = TEST_RESOURCE_DIR "/Cube-Points-Only.obj";
 const char* TEST_SIMPLE_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal-Simple.mtl";
 
+// 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";
+
 Integration::Bitmap* CreateBitmap( unsigned int imageWidth, unsigned int imageHeight, unsigned int initialColor, Pixel::Format pixelFormat )
 {
   Integration::Bitmap* bitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_RETAIN );
@@ -252,7 +257,7 @@ int UtcDaliVisualFactoryGet(void)
   VisualFactory newFactory = VisualFactory::Get();
   DALI_TEST_CHECK( newFactory );
 
-  // Check that renderer factory is a singleton
+  // Check that visual factory is a singleton
   DALI_TEST_CHECK(factory == newFactory);
 
   END_TEST;
@@ -573,7 +578,7 @@ int UtcDaliVisualFactoryDefaultOffsetsGradientVisual(void)
 int UtcDaliVisualFactoryGetImageVisual1(void)
 {
   ToolkitTestApplication application;
-  tet_infoline( "UtcDaliVisualFactoryGetImageVisual1: Request image renderer with a Property::Map" );
+  tet_infoline( "UtcDaliVisualFactoryGetImageVisual1: Request image visual with a Property::Map" );
 
   VisualFactory factory = VisualFactory::Get();
   DALI_TEST_CHECK( factory );
@@ -613,7 +618,7 @@ int UtcDaliVisualFactoryGetImageVisual1(void)
 int UtcDaliVisualFactoryGetImageVisual2(void)
 {
   ToolkitTestApplication application;
-  tet_infoline( "UtcDaliVisualFactoryGetImageVisual2: Request image renderer with an image handle" );
+  tet_infoline( "UtcDaliVisualFactoryGetImageVisual2: Request image visual with an image handle" );
 
   VisualFactory factory = VisualFactory::Get();
   DALI_TEST_CHECK( factory );
@@ -644,10 +649,170 @@ int UtcDaliVisualFactoryGetImageVisual2(void)
   END_TEST;
 }
 
+int UtcDaliVisualFactoryGetImageVisual3(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetImageVisual3: Request image visual with a Property::Map, test custom wrap mode and pixel area with atlasing" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  // Test wrap mode with atlasing. Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+  const int width=34;
+  const int height=34;
+  const Vector4 pixelArea(-0.5f, -0.5f, 2.f, 2.f);
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  gImage_34_RGBA );
+  propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH, width );
+  propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT, height );
+  propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, true );
+  propertyMap.Insert( ImageVisual::Property::PIXEL_AREA, pixelArea );
+  propertyMap.Insert( ImageVisual::Property::WRAP_MODE_U, WrapMode::MIRRORED_REPEAT );
+  propertyMap.Insert( ImageVisual::Property::WRAP_MODE_V, WrapMode::REPEAT );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  Actor actor = Actor::New();
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& texParameterTrace = gl.GetTexParameterTrace();
+  texParameterTrace.Enable( true );
+
+  actor.SetSize( 200.f, 200.f );
+  Stage::GetCurrent().Add( actor );
+  visual.SetOnStage( actor );
+
+  // loading started
+  application.SendNotification();
+  application.Render();
+  application.Render();
+  application.SendNotification();
+  BitmapLoader loader = BitmapLoader::GetLatestCreated();
+  DALI_TEST_CHECK( loader );
+  loader.WaitForLoading();// waiting until the image to be loaded
+  DALI_TEST_CHECK( loader.IsLoaded() );
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  // WITH atlasing, the wrapping is handled manually in shader, so the following gl function should not be called
+  std::stringstream out;
+  out << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_S << ", " << GL_MIRRORED_REPEAT;
+  DALI_TEST_CHECK( !texParameterTrace.FindMethodAndParams("TexParameteri", out.str()) );
+  out.str("");
+  out << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_T << ", " << GL_REPEAT;
+  DALI_TEST_CHECK( !texParameterTrace.FindMethodAndParams("TexParameteri", out.str()) );
+
+  // test the uniforms which used to handle the wrap mode
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  Property::Value pixelAreaValue = renderer.GetProperty( renderer.GetPropertyIndex( "pixelArea" ) );
+  DALI_TEST_EQUALS( pixelAreaValue.Get<Vector4>(), pixelArea, TEST_LOCATION );
+  Vector4 pixelAreaUniform;
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "pixelArea", pixelAreaUniform ) );
+  DALI_TEST_EQUALS( pixelArea, pixelAreaUniform, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  Property::Value wrapModeValue = renderer.GetProperty( renderer.GetPropertyIndex( "wrapMode" ) );
+  Vector2 wrapMode( WrapMode::MIRRORED_REPEAT-1, WrapMode::REPEAT-1 );
+  DALI_TEST_EQUALS( wrapModeValue.Get<Vector2>(), wrapMode, TEST_LOCATION );
+  Vector2 wrapModeUniform;
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector2>( "wrapMode", wrapModeUniform ) );
+  DALI_TEST_EQUALS( wrapMode, wrapModeUniform, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  visual.SetOffStage( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetImageVisual4(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetImageVisual4: Request image visual with a Property::Map, test custom wrap mode and pixel area without atlasing" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  // Test wrap mode without atlasing. Image with a size bigger than 512*512 will NOT be uploaded as a part of the atlas.
+  const int width=600;
+  const int height=600;
+  const Vector4 pixelArea(-0.5f, -0.5f, 2.f, 2.f);
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  gImage_600_RGB );
+  propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH, width );
+  propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT, height );
+  propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, true );
+  propertyMap.Insert( ImageVisual::Property::PIXEL_AREA, pixelArea );
+  propertyMap.Insert( ImageVisual::Property::WRAP_MODE_U, WrapMode::MIRRORED_REPEAT );
+  propertyMap.Insert( ImageVisual::Property::WRAP_MODE_V, WrapMode::REPEAT );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  Actor actor = Actor::New();
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& texParameterTrace = gl.GetTexParameterTrace();
+  texParameterTrace.Enable( true );
+
+  actor.SetSize( 200.f, 200.f );
+  Stage::GetCurrent().Add( actor );
+  visual.SetOnStage( actor );
+
+  // loading started
+  application.SendNotification();
+  application.Render();
+  application.Render();
+  application.SendNotification();
+  BitmapLoader loader = BitmapLoader::GetLatestCreated();
+  DALI_TEST_CHECK( loader );
+  loader.WaitForLoading();// waiting until the image to be loaded
+  DALI_TEST_CHECK( loader.IsLoaded() );
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  // WITHOUT atlasing, the wrapping is handled by setting gl texture parameters
+  std::stringstream out;
+  out << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_S << ", " << GL_MIRRORED_REPEAT;
+  DALI_TEST_CHECK( texParameterTrace.FindMethodAndParams("TexParameteri", out.str()) );
+  out.str("");
+  out << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_T << ", " << GL_REPEAT;
+  DALI_TEST_CHECK( texParameterTrace.FindMethodAndParams("TexParameteri", out.str()) );
+
+  // test the uniforms which used to handle the wrap mode
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  Property::Value pixelAreaValue = renderer.GetProperty( renderer.GetPropertyIndex( "pixelArea" ) );
+  DALI_TEST_EQUALS( pixelAreaValue.Get<Vector4>(), pixelArea, TEST_LOCATION );
+  Vector4 pixelAreaUniform;
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "pixelArea", pixelAreaUniform ) );
+  DALI_TEST_EQUALS( pixelArea, pixelAreaUniform, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  Property::Index wrapModeIndex = renderer.GetPropertyIndex( "wrapMode" );
+  DALI_TEST_CHECK(wrapModeIndex == Property::INVALID_INDEX);
+
+  visual.SetOffStage( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
 int UtcDaliVisualFactoryGetNPatchVisual1(void)
 {
   ToolkitTestApplication application;
-  tet_infoline( "UtcDaliVisualFactoryGetNPatchVisual1: Request 9-patch renderer with a Property::Map" );
+  tet_infoline( "UtcDaliVisualFactoryGetNPatchVisual1: Request 9-patch visual with a Property::Map" );
 
   VisualFactory factory = VisualFactory::Get();
   DALI_TEST_CHECK( factory );
@@ -706,7 +871,7 @@ int UtcDaliVisualFactoryGetNPatchVisual1(void)
 int UtcDaliVisualFactoryGetNPatchVisual2(void)
 {
   ToolkitTestApplication application;
-  tet_infoline( "UtcDaliVisualFactoryGetNPatchVisual2: Request n-patch renderer with a Property::Map" );
+  tet_infoline( "UtcDaliVisualFactoryGetNPatchVisual2: Request n-patch visual with a Property::Map" );
 
   VisualFactory factory = VisualFactory::Get();
   DALI_TEST_CHECK( factory );
@@ -774,7 +939,7 @@ int UtcDaliVisualFactoryGetNPatchVisual2(void)
 int UtcDaliVisualFactoryGetNPatchVisual3(void)
 {
   ToolkitTestApplication application;
-  tet_infoline( "UtcDaliVisualFactoryGetNPatchVisual3: Request 9-patch renderer with an image url" );
+  tet_infoline( "UtcDaliVisualFactoryGetNPatchVisual3: Request 9-patch visual with an image url" );
 
   VisualFactory factory = VisualFactory::Get();
   DALI_TEST_CHECK( factory );
@@ -974,7 +1139,7 @@ int UtcDaliVisualFactoryGetSvgVisual(void)
   END_TEST;
 }
 
-//Creates a mesh renderer from the given propertyMap and tries to load it on stage in the given application.
+//Creates a mesh visual from the given propertyMap and tries to load it on stage in the given application.
 //This is expected to succeed, which will then pass the test.
 void MeshVisualLoadsCorrectlyTest( Property::Map& propertyMap, ToolkitTestApplication& application )
 {
@@ -1697,7 +1862,7 @@ int UtcDaliVisualFactoryGetPrimitiveVisual17(void)
   END_TEST;
 }
 
-//Test if primitive shape renderer handles the case of not being passed a specific shape to use.
+//Test if primitive shape visual handles the case of not being passed a specific shape to use.
 int UtcDaliVisualFactoryGetPrimitiveVisualN1(void)
 {
   //Set up test application first, so everything else can be handled.
index 209ecda..766567f 100644 (file)
@@ -109,7 +109,7 @@ develapipopupdir =              $(develapicontrolsdir)/popup
 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)
@@ -142,6 +142,7 @@ develapitextselectionpopup_HEADERS = $(devel_api_text_controls_header_files)
 # public api source
 publicapidir =                     $(topleveldir)/public-api
 publicapicontrolsdir =             $(publicapidir)/controls
+publicapiimageloaderdir =          $(publicapidir)/image-loader
 publicapiaccessibilitymanagerdir = $(publicapidir)/accessibility-manager
 publicapialignmentdir =            $(publicapicontrolsdir)/alignment
 publicapibuttonsdir =              $(publicapicontrolsdir)/buttons
@@ -165,6 +166,7 @@ publicapivisualsdir =              $(publicapidir)/visuals
 # public api headers
 publicapi_HEADERS =                     $(public_api_header_files)
 publicapicontrols_HEADERS =             $(public_api_controls_header_files)
+publicapiimageloader_HEADERS =          $(public_api_image_loader_header_files)
 publicapiaccessibilitymanager_HEADERS = $(public_api_accessibility_manager_header_files)
 publicapialignment_HEADERS =            $(public_api_alignment_header_files)
 publicapibuttons_HEADERS =              $(public_api_buttons_header_files)
index 70d518e..c4da486 100644 (file)
@@ -349,6 +349,8 @@ ALIASES += SINCE_1_1="@since 1.1"
 ALIASES += SINCE_1_2_2="@since 1.2.2"
 ALIASES += SINCE_1_2_4="@since 1.2.4"
 ALIASES += SINCE_1_2_5="@since 1.2.5"
+ALIASES += SINCE_1_2_10="@since 1.2.10"
+ALIASES += SINCE_1_2_14="@since 1.2.14"
 
 ALIASES += DEPRECATED_1_0="@deprecated Deprecated since 1.0"
 ALIASES += DEPRECATED_1_1="@deprecated Deprecated since 1.1"
@@ -370,6 +372,8 @@ ALIASES += REMARK_INTERNET=""
 #ALIASES += SINCE_1_2_2="\par Since:\n 3.0, DALi version 1.2.2"
 #ALIASES += SINCE_1_2_4="\par Since:\n 3.0, DALi version 1.2.4"
 #ALIASES += SINCE_1_2_5="\par Since:\n 3.0, DALi version 1.2.5"
+#ALIASES += SINCE_1_2_10="\par Since:\n 3.0, DALi version 1.2.10"
+#ALIASES += SINCE_1_2_14="\par Since:\n 3.0, DALi version 1.2.14"
 
 ## DALi has no deprecated API in Tizen 2.4 because it's DALi's first release.
 ## Thus deprecated APIs in DALi 1.0.xx will be deprecated in Tizen 3.0.
index e6f1eaa..763f973 100644 (file)
@@ -47,6 +47,9 @@
 #include <dali-toolkit/public-api/controls/text-controls/text-label.h>
 #include <dali-toolkit/public-api/controls/video-view/video-view.h>
 
+#include <dali-toolkit/public-api/image-loader/async-image-loader.h>
+#include <dali-toolkit/public-api/image-loader/sync-image-loader.h>
+
 #include <dali-toolkit/public-api/accessibility-manager/accessibility-manager.h>
 
 #include <dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h>
index cc12134..64432b4 100644 (file)
@@ -19,7 +19,7 @@
  */
 
 // EXTERNAL INCLUDES
-#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/rendering/texture.h>
 
 namespace Dali
 {
@@ -28,7 +28,7 @@ namespace Toolkit
 {
 
 /**
- * @brief PageFactory is an abstract interface for providing images to PageTurnView
+ * @brief PageFactory is an abstract interface for providing textures to PageTurnView
  * Each page is identified by a unique ID, and has a linear order from 0 to GetNumberOfPages()-1
  *
  * @SINCE_1_1.4
@@ -41,7 +41,6 @@ public:
 
   /**
    * @brief Virtual destructor
-   * @SINCE_1_1.4
    */
   virtual ~PageFactory(){};
 
@@ -49,26 +48,24 @@ public:
    * @brief Query the number of pages available from the factory.
    *
    * The maximum available page has an ID of GetNumberOfPages()-1.
-   * @SINCE_1_1.4
    * @return The page count.
    */
   virtual unsigned int GetNumberOfPages() = 0;
 
   /**
-   * @brief Create an actor to represent the page content.
-   * @SINCE_1_1.30
+   * @brief Return the texture for the page
    *
-   * If no valid image provided, a broken image is displayed.
-   * For double-sided page( PageTurnLandscapeView ), the left half of image is used as page front side, and the right half as page back side.
+   * For double-sided page( PageTurnLandscapeView ), the left half of texture is used as page front side, and the right half as page back side.
+   *
+   * @note Must return a valid texture handle!
    *
    * @param[in] pageId The ID of the page to create.
    * @return An actor, or an uninitialized pointer if the ID is out of range.
    */
-  virtual Image NewPage( unsigned int pageId ) = 0;
+  virtual Texture NewPage( unsigned int pageId ) = 0;
 
   /**
    * @brief Retrieve the extension for this factory
-   * @SINCE_1_1.30
    *
    * @return The extension if available, NULL otherwise.
    */
index 7e4dde4..77ee5c6 100755 (executable)
@@ -19,7 +19,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/atlas-upload-observer.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 \
@@ -71,8 +72,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/atlas-upload-observer.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/atlas-upload-observer.cpp b/dali-toolkit/devel-api/image-loader/atlas-upload-observer.cpp
new file mode 100644 (file)
index 0000000..f362edc
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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 "atlas-upload-observer.h"
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/image-loader/image-atlas-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+AtlasUploadObserver::AtlasUploadObserver()
+{}
+
+AtlasUploadObserver::~AtlasUploadObserver()
+{
+  // Notify the registerd ImageAtlas object about the destruction of observer.
+  const std::size_t size( mAtlasList.Count() );
+  for( std::size_t i = 0; i < size; ++i )
+  {
+    if( mAtlasList[i] )
+    {
+      mAtlasList[i]->ObserverDestroyed( this );
+    }
+  }
+  mAtlasList.Clear();
+}
+
+void AtlasUploadObserver::Register( Internal::ImageAtlas& imageAtlas )
+{
+  // Add to the list so that the ImageAtlas could get notified in the destructor.
+  // If the same atlas is exist in the list already, we would still save the duplicated copy.
+  mAtlasList.PushBack( &imageAtlas );
+}
+
+void AtlasUploadObserver::Unregister( Internal::ImageAtlas& imageAtlas )
+{
+  const std::size_t size( mAtlasList.Count() );
+  for( std::size_t i = 0; i < size; i++ )
+  {
+    if( mAtlasList[i] == &imageAtlas )
+    {
+      // Remove from list
+      mAtlasList.Erase( mAtlasList.Begin() + i );
+      // If there are duplicated copies of same pointer, only the first one is removed
+      return;
+    }
+  }
+}
+
+}
+
+}
diff --git a/dali-toolkit/devel-api/image-loader/atlas-upload-observer.h b/dali-toolkit/devel-api/image-loader/atlas-upload-observer.h
new file mode 100644 (file)
index 0000000..2688c1a
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef DALI_TOOLKIT_ATLAS_UPLOAD_OBSERVER_H
+#define DALI_TOOLKIT_ATLAS_UPLOAD_OBSERVER_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.
+ *
+ */
+
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/signals/callback.h>
+
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+class ImageAtlas;
+}
+
+/**
+ * @brief Base class used to observe the upload status of the ImageAtlas when requesting an image atlasing.
+ *
+ * Derived class should implement the UploadCompleted method which would get executed once the texture is ready.
+ */
+class DALI_IMPORT_API AtlasUploadObserver
+{
+public:
+
+  /**
+   * @brief Constructor.
+   */
+  AtlasUploadObserver();
+
+  /**
+   * @brief Virtual destructor.
+   */
+  virtual ~AtlasUploadObserver();
+
+  /**
+   * The action to be taken once the upload is completed.
+   */
+  virtual void UploadCompleted() = 0;
+
+public: // not intended for developer, called by ImageAtlas internally to get notified when this observer dies
+
+  /**
+   * @brief Register an ImageAtlas which be notified when the observer is destructing.
+   * @param[in] imageAtlas The ImageAtlas object to get notification about the destruction of the observer.
+   */
+  void Register( Internal::ImageAtlas& imageAtlas );
+
+  /**
+   * @brief Unregister an ImageAtlas which be notified when the observer is destructing.
+   * @param[in] imageAtlas The ImageAtlas object to get notification about the destruction of the observer.
+   */
+  void Unregister( Internal::ImageAtlas& imageAtlas );
+
+private:
+
+  Vector<Internal::ImageAtlas*> mAtlasList; ///< The list of the registered ImageAtlas object
+
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_ATLAS_UPLOAD_OBSERVER_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 );
@@ -74,7 +80,17 @@ bool ImageAtlas::Upload( Vector4& textureRect,
                          FittingMode::Type fittingMode,
                          bool orientationCorrection )
 {
-  return GetImplementation(*this).Upload( textureRect, url, size, fittingMode, orientationCorrection );
+  return Upload( textureRect, url, size, fittingMode, orientationCorrection, NULL );
+}
+
+bool ImageAtlas::Upload( Vector4& textureRect,
+                         const std::string& url,
+                         ImageDimensions size,
+                         FittingMode::Type fittingMode,
+                         bool orientationCorrection,
+                         AtlasUploadObserver* atlasUploadObserver )
+{
+  return GetImplementation(*this).Upload( textureRect, url, size, fittingMode, orientationCorrection, atlasUploadObserver );
 }
 
 bool ImageAtlas::Upload( Vector4& textureRect, PixelData pixelData )
 #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>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/image-loader/atlas-upload-observer.h>
 
 namespace Dali
 {
@@ -37,10 +40,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 +94,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 texture
+   */
+  Texture GetAtlas();
+
+  /*
+   * @brief Query what percentage of space is been occupied in the atlas.
    *
-   * @return the atlas image with type of Dali::Atlas
+   * @return The occupancy rate of the atlas.
    */
-  Image GetAtlas();
+  float GetOccupancyRate() const;
 
   /**
    * @brief Set the broken image which is used to replace the image if loading fails.
@@ -107,7 +117,7 @@ public:
   /**
    * @brief Upload a resource image to the atlas.
    *
-   * @note To make the atlasing efficient, an valid size should be provided.
+   * @note To make the atlasing efficient, a valid size should be provided.
    *       If size is not provided, then the image file will be opened to read the actual size for loading.
    *       Do not set a size that is bigger than the actual image size, as the up-scaling is not available,
    *       the content of the area not covered by actual image is undefined, it will not be cleared.
@@ -128,6 +138,32 @@ public:
                bool orientationCorrection = true );
 
   /**
+   * @brief Upload a resource image to the atlas.
+   *
+   * @note To make the atlasing efficient, a valid size should be provided.
+   *       If size is not provided, then the image file will be opened to read the actual size for loading.
+   *       Do not set a size that is bigger than the actual image size, as the up-scaling is not available,
+   *       the content of the area not covered by actual image is undefined, it will not be cleared.
+   *
+   * SamplingMode::BOX_THEN_LINEAR is used to sampling pixels from the input image while fitting it to desired size.
+   *
+   * @param [out] textureRect The texture area of the resource image in the atlas.
+   * @param [in] url The URL of the resource image file to use.
+   * @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] orientationCorrection Reorient the image to respect any orientation metadata in its header.
+   * @param[in] atlasUploadObserver The observer to observe the upload state inside the ImageAtlas.
+   * @return True if there is enough space to fit this image in,false otherwise.
+   * @note The valid callback function here is required to have the signature of void( void ).
+   */
+  bool Upload( Vector4& textureRect,
+               const std::string& url,
+               ImageDimensions size,
+               FittingMode::Type fittingMode,
+               bool orientationCorrection,
+               AtlasUploadObserver* atlasUploadObserver );
+
+  /**
    * @brief Upload a pixel buffer to atlas
    *
    * @param [out] textureRect The texture area of the resource image in the atlas.
index ddaf292..8698aac 100644 (file)
 #include <cstring> // for strcmp
 #include <dali/public-api/animation/animation.h>
 #include <dali/public-api/animation/constraint.h>
-#include <dali/public-api/images/resource-image.h>
 #include <dali/public-api/object/type-registry.h>
 #include <dali/public-api/object/type-registry-helper.h>
-#include <dali/devel-api/images/texture-set-image.h>
 #include <dali/integration-api/debug.h>
 
 // INTERNAL INCLUDES
@@ -39,9 +37,6 @@ using namespace Dali;
 
 namespace //Unnamed namespace
 {
-// broken image is loaded if there is no valid image provided for the page
-const char * const BROKEN_IMAGE_URL( DALI_IMAGE_DIR "broken.png");
-
 // properties set on shader, these properties have the constant value in regardless of the page status
 const char * const PROPERTY_SPINE_SHADOW ( "uSpineShadowParameter" ); // uniform for both spine and turn effect
 
@@ -282,14 +277,13 @@ PageTurnView::Page::Page()
   propertyTurnDirection = actor.RegisterProperty(PROPERTY_TURN_DIRECTION, -1.f);
 }
 
-void PageTurnView::Page::SetImage( Image image  )
+void PageTurnView::Page::SetTexture( Texture texture )
 {
   if( !textureSet )
   {
     textureSet = TextureSet::New();
   }
-
-  TextureSetImage( textureSet, 0u, image );
+  textureSet.SetTexture( 0u, texture );
 }
 
 void PageTurnView::Page::UseEffect(Shader newShader)
@@ -398,7 +392,7 @@ void PageTurnView::OnInitialize()
     Self().Add( mPages[i].actor );
   }
 
-  // create the layer for turning images
+  // create the layer for turning pages
   mTurningPageLayer = Layer::New();
   mTurningPageLayer.SetAnchorPoint( AnchorPoint::CENTER_LEFT );
   mTurningPageLayer.SetBehavior(Layer::LAYER_3D);
@@ -584,13 +578,9 @@ void PageTurnView::AddPage( int pageIndex )
   {
     int index = pageIndex % NUMBER_OF_CACHED_PAGES;
 
-    Image newPageImage;
-    newPageImage = mPageFactory->NewPage( pageIndex );
-
-    if( !newPageImage ) // load the broken image
-    {
-      newPageImage = ResourceImage::New( BROKEN_IMAGE_URL );
-    }
+    Texture newPage;
+    newPage = mPageFactory->NewPage( pageIndex );
+    DALI_ASSERT_ALWAYS( newPage && "must pass in valid texture" );
 
     bool isLeftSide = ( pageIndex < mCurrentPageIndex );
     if( mPages[index].isTurnBack != isLeftSide )
@@ -602,11 +592,11 @@ void PageTurnView::AddPage( int pageIndex )
     mPages[index].actor.SetOrientation( Degree( degree ), Vector3::YAXIS );
     mPages[index].actor.SetVisible( false );
     mPages[index].UseEffect( mSpineEffectShader, mGeometry );
-    mPages[index].SetImage( newPageImage );
+    mPages[index].SetTexture( newPage );
 
     // For Portrait, nothing to do
     // For Landscape, set the parent origin to CENTER
-     OnAddPage( mPages[index].actor, isLeftSide );
+    OnAddPage( mPages[index].actor, isLeftSide );
   }
 }
 
index 2d40717..73aff02 100644 (file)
@@ -57,10 +57,10 @@ protected:
     ~Page(){};
 
     /**
-     * Set the page image content
-     * @param[in] image The content of the page.
+     * Set the page texture content
+     * @param[in] texture The content of the page.
      */
-    void SetImage( Image image );
+    void SetTexture( Texture texture );
 
     /**
      * Apply an effect onto the page actor.
index 78940ad..9bb071a 100644 (file)
@@ -83,9 +83,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..06065b7
--- /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( 0u ),
+  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 dimensions,
+                                 FittingMode::Type fittingMode,
+                                 SamplingMode::Type samplingMode,
+                                 bool orientationCorrection )
+{
+  if( !mIsLoadThreadStarted )
+  {
+    mLoadThread.Start();
+    mIsLoadThreadStarted = true;
+  }
+
+  BitmapLoader loader = BitmapLoader::New( url, dimensions, 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..92a1652
--- /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/public-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 dimensions,
+                 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& handle )
+{
+  DALI_ASSERT_ALWAYS( handle && "AsyncImageLoader handle is empty" );
+
+  const BaseObject& object = handle.GetBaseObject();
+
+  return static_cast<const Internal::AsyncImageLoader&>( object );
+}
+
+inline Internal::AsyncImageLoader& GetImplementation( Toolkit::AsyncImageLoader& handle )
+{
+  DALI_ASSERT_ALWAYS( handle && "AsyncImageLoader handle is empty" );
+
+  BaseObject& object = handle.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,52 @@ 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 )
+  const std::size_t count = mLoadingTaskInfoContainer.Count();
+  for( std::size_t i=0; i < count; ++i )
   {
-    // 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();
+    // Call unregister to every observer in the list.
+    // Note that, the Atlas can be registered to same observer multiple times, and the Unregister method only remove one item each time.
+    // In this way, the atlas is actually detached from a observer either every upload call invoked by this observer is completed or atlas is destroyed.
+    if( mLoadingTaskInfoContainer[i]->observer )
+    {
+      mLoadingTaskInfoContainer[i]->observer->Unregister( *this );
+    }
   }
+
+  mLoadingTaskInfoContainer.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 );
@@ -86,7 +94,8 @@ bool ImageAtlas::Upload( Vector4& textureRect,
                          const std::string& url,
                          ImageDimensions size,
                          FittingMode::Type fittingMode,
-                         bool orientationCorrection )
+                         bool orientationCorrection,
+                         AtlasUploadObserver* atlasUploadObserver )
 {
   ImageDimensions dimensions = size;
   ImageDimensions zero;
@@ -97,7 +106,7 @@ bool ImageAtlas::Upload( Vector4& textureRect,
     {
       if( !mBrokenImageUrl.empty() )
       {
-        return Upload( textureRect, mBrokenImageUrl, mBrokenImageSize, FittingMode::DEFAULT, true );
+        return Upload( textureRect, mBrokenImageUrl, mBrokenImageSize, FittingMode::DEFAULT, true, atlasUploadObserver );
       }
       else
       {
@@ -107,31 +116,25 @@ 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 );
+    mLoadingTaskInfoContainer.PushBack( new LoadingTaskInfo( loadId, packPositionX, packPositionY, dimensions.GetWidth(), dimensions.GetHeight(), atlasUploadObserver ) );
     // apply the half pixel correction
     textureRect.x = ( static_cast<float>( packPositionX ) +0.5f ) / mWidth; // left
     textureRect.y = ( static_cast<float>( packPositionY ) +0.5f ) / mHeight; // right
     textureRect.z = ( static_cast<float>( packPositionX + dimensions.GetX() )-0.5f ) / mWidth; // right
     textureRect.w = ( static_cast<float>( packPositionY + dimensions.GetY() )-0.5f ) / mHeight;// bottom
 
+    if( atlasUploadObserver )
+    {
+      // register to the observer,
+      // Not that a matching unregister call should be invoked in UploadToAtlas if the observer is still alive by then.
+      atlasUploadObserver->Register( *this );
+    }
+
     return true;
   }
 
@@ -144,7 +147,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 +169,54 @@ void ImageAtlas::Remove( const Vector4& textureRect )
                        static_cast<SizeType>((textureRect.w-textureRect.y)*mHeight+1.f) );
 }
 
-void ImageAtlas::UploadToAtlas()
+void ImageAtlas::ObserverDestroyed( AtlasUploadObserver* observer )
+{
+  const std::size_t count = mLoadingTaskInfoContainer.Count();
+  for( std::size_t i=0; i < count; ++i )
+  {
+    if( mLoadingTaskInfoContainer[i]->observer == observer )
+    {
+      // the observer is destructing, so its member function should not be called anymore
+      mLoadingTaskInfoContainer[i]->observer = NULL;
+    }
+  }
+}
+
+void ImageAtlas::UploadToAtlas( uint32_t id, PixelData pixelData )
 {
-  while( LoadingTask* next = mCompleteQueue.NextTask() )
+  if(  mLoadingTaskInfoContainer[0]->loadTaskId == id)
   {
-    if( ! next->loader.IsLoaded() )
+    Rect<unsigned int> packRect( mLoadingTaskInfoContainer[0]->packRect  );
+    if( !pixelData || ( pixelData.GetWidth() ==0 && pixelData.GetHeight() == 0 ))
     {
       if(!mBrokenImageUrl.empty()) // replace with the broken image
       {
-        UploadBrokenImage( next->packRect );
+        UploadBrokenImage( 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() < packRect.width || pixelData.GetHeight() < 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(),
+            packRect.width, packRect.height );
       }
 
-      mAtlas.Upload( next->loader.GetPixelData(), next->packRect.x, next->packRect.y );
+      mAtlas.Upload( pixelData, 0u, 0u, packRect.x, packRect.y, packRect.width, packRect.height );
+    }
+
+    if( mLoadingTaskInfoContainer[0]->observer )
+    {
+      mLoadingTaskInfoContainer[0]->observer->UploadCompleted();
+      mLoadingTaskInfoContainer[0]->observer->Unregister( *this );
     }
 
-    delete next;
+    mLoadingTaskInfoContainer.Erase( mLoadingTaskInfoContainer.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 +247,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>
+#include <dali/devel-api/common/owner-container.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/internal/image-loader/atlas-packer.h>
+#include <dali-toolkit/public-api/image-loader/async-image-loader.h>
 
 namespace Dali
 {
@@ -37,7 +40,7 @@ namespace Toolkit
 namespace Internal
 {
 
-class ImageAtlas : public BaseObject
+class ImageAtlas : public BaseObject, public ConnectionTracker
 {
 public:
 
@@ -59,7 +62,12 @@ public:
   /**
    * @copydoc Toolkit::ImageAtlas::GetAtlas
    */
-  Image GetAtlas();
+  Texture GetAtlas();
+
+  /**
+   * @copydoc Toolkit::ImageAtlas::GetOccupancyRate
+   */
+  float GetOccupancyRate() const;
 
   /**
    * @copydoc Toolkit::ImageAtlas::SetBrokenImage
@@ -73,7 +81,8 @@ public:
                const std::string& url,
                ImageDimensions size,
                FittingMode::Type fittingMode,
-               bool orientationCorrection);
+               bool orientationCorrection,
+               AtlasUploadObserver* atlasUploadObserver );
 
   /**
    * @copydoc Toolkit::ImageAtlas::Upload( Vector4&, PixelData )
@@ -85,6 +94,11 @@ public:
    */
   void Remove( const Vector4& textureRect );
 
+  /**
+   * Resets the destroying observer pointer so that we know not to call methods of this object any more.
+   */
+  void ObserverDestroyed( AtlasUploadObserver* observer );
+
 protected:
 
   /**
@@ -95,16 +109,16 @@ protected:
 private:
 
   /**
-   * Upload the bitmap to atlas when the image is loaded in the worker thread.
+   * @copydoc PixelDataRequester::ProcessPixels
    */
-  void UploadToAtlas();
+  void UploadToAtlas( uint32_t 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 +128,39 @@ private:
 
 private:
 
-  Atlas                mAtlas;
-  AtlasPacker          mPacker;
-
-  LoadQueue            mLoadQueue;
-  CompleteQueue        mCompleteQueue;
-  ImageLoadThread      mLoadingThread;
+  /**
+   * Each loading task( identified with an ID ) is associated with a rect region for packing the loaded pixel data into the atlas,
+   * and an AtlasUploadObserver whose UploadCompleted method should get executed once the sub texture is ready.
+   */
+  struct LoadingTaskInfo
+  {
+    LoadingTaskInfo( unsigned short loadTaskId,
+                     unsigned int packPositionX,
+                     unsigned int packPositionY,
+                     unsigned int width,
+                     unsigned int height,
+                     AtlasUploadObserver* observer )
+    : loadTaskId( loadTaskId ),
+      packRect( packPositionX, packPositionY, width, height ),
+      observer( observer )
+    {}
+
+    unsigned short loadTaskId;
+    Rect<unsigned int> packRect;
+    AtlasUploadObserver* observer;
+  };
+
+  OwnerContainer<LoadingTaskInfo*> mLoadingTaskInfoContainer;
+
+  Texture                   mAtlas;
+  AtlasPacker               mPacker;
+  Toolkit::AsyncImageLoader mAsyncLoader;
+  std::string               mBrokenImageUrl;
+  ImageDimensions           mBrokenImageSize;
+  float                     mWidth;
+  float                     mHeight;
+  Pixel::Format             mPixelFormat;
 
-  std::string          mBrokenImageUrl;
-  ImageDimensions      mBrokenImageSize;
-  float                mWidth;
-  float                mHeight;
-  Pixel::Format        mPixelFormat;
-  bool                 mLoadingThreadStarted;
 
 };
 
@@ -27,111 +27,131 @@ 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)
+  if( wasEmpty )
   {
     // wake up the image loading thread
     mConditionalWait.Notify();
   }
 }
 
-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..fe01571 100644 (file)
@@ -51,7 +51,8 @@ TextureSet ImageAtlasManager::Add( Vector4& textureRect,
                                  const std::string& url,
                                  ImageDimensions size,
                                  FittingMode::Type fittingMode,
-                                 bool orientationCorrection )
+                                 bool orientationCorrection,
+                                 AtlasUploadObserver* atlasUploadObserver )
 {
   ImageDimensions dimensions = size;
   ImageDimensions zero;
@@ -71,7 +72,7 @@ TextureSet ImageAtlasManager::Add( Vector4& textureRect,
   unsigned int i = 0;
   for( AtlasContainer::iterator iter = mAtlasList.begin(); iter != mAtlasList.end(); ++iter)
   {
-    if( (*iter).Upload( textureRect, url, size, fittingMode, orientationCorrection ) )
+    if( (*iter).Upload( textureRect, url, size, fittingMode, orientationCorrection, atlasUploadObserver ) )
     {
       return mTextureSetList[i];
     }
@@ -79,12 +80,12 @@ TextureSet ImageAtlasManager::Add( Vector4& textureRect,
   }
 
   CreateNewAtlas();
-  mAtlasList.back().Upload( textureRect, url, size, fittingMode, orientationCorrection );
+  mAtlasList.back().Upload( textureRect, url, size, fittingMode, orientationCorrection, atlasUploadObserver );
   return mTextureSetList.back();
 }
 
 TextureSet ImageAtlasManager::Add( Vector4& textureRect,
-                                 PixelData pixelData )
+                                   PixelData pixelData )
 {
 
   // big buffer, atlasing is not applied
@@ -142,7 +143,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..5907ca2 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
 {
@@ -32,6 +32,8 @@ namespace Dali
 namespace Toolkit
 {
 
+class AtlasUploadObserver;
+
 namespace Internal
 {
 
@@ -65,14 +67,15 @@ public:
    * @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] orientationCorrection Reorient the image to respect any orientation metadata in its header.
+   * @param [in] atlasUploadObserver The object to observe the uploading state inside ImageAtlas.
    * @return The texture set containing the image.
    */
   TextureSet Add( Vector4& textureRect,
-                const std::string& url,
-                ImageDimensions size = ImageDimensions(),
-                FittingMode::Type fittingMode = FittingMode::DEFAULT,
-                bool orientationCorrection = true );
-
+                  const std::string& url,
+                  ImageDimensions size = ImageDimensions(),
+                  FittingMode::Type fittingMode = FittingMode::DEFAULT,
+                  bool orientationCorrection = true,
+                  AtlasUploadObserver* atlasUploadObserver = NULL );
   /**
    * @brief Add a pixel buffer to the atlas
    *
index 98f9734..4bc0d02 100644 (file)
@@ -57,6 +57,8 @@ 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 IMAGE_WRAP_MODE_U("wrapModeU");
+const char * const IMAGE_WRAP_MODE_V("wrapModeV");
 const char * const SYNCHRONOUS_LOADING( "synchronousLoading" );
 
 // fitting modes
@@ -79,7 +81,16 @@ DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, NO_FILTER )
 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, DONT_CARE )
 DALI_ENUM_TO_STRING_TABLE_END( SAMPLING_MODE )
 
+// wrap modes
+DALI_ENUM_TO_STRING_TABLE_BEGIN( WRAP_MODE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, DEFAULT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, CLAMP_TO_EDGE )
+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 )
+
 const std::string PIXEL_AREA_UNIFORM_NAME = "pixelArea";
+const std::string WRAP_MODE_UNIFORM_NAME = "wrapMode";
 
 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
 
@@ -89,7 +100,6 @@ const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
   attribute mediump vec2 aPosition;\n
   uniform mediump mat4 uMvpMatrix;\n
   uniform mediump vec3 uSize;\n
-  uniform mediump vec4 uAtlasRect;\n
   uniform mediump vec4 pixelArea;
   varying mediump vec2 vTexCoord;\n
   \n
@@ -99,12 +109,12 @@ const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
     vertexPosition.xyz *= uSize;\n
     vertexPosition = uMvpMatrix * vertexPosition;\n
     \n
-    vTexCoord = mix( uAtlasRect.xy, uAtlasRect.zw, pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5) ) );\n
+    vTexCoord = pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5) );\n
     gl_Position = vertexPosition;\n
   }\n
 );
 
-const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+const char* FRAGMENT_SHADER_NO_ATLAS = DALI_COMPOSE_SHADER(
   varying mediump vec2 vTexCoord;\n
   uniform sampler2D sTexture;\n
   uniform lowp vec4 uColor;\n
@@ -115,6 +125,42 @@ const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
   }\n
 );
 
+const char* FRAGMENT_SHADER_ATLAS_CLAMP = DALI_COMPOSE_SHADER(
+    varying mediump vec2 vTexCoord;\n
+    uniform sampler2D sTexture;\n
+    uniform mediump vec4 uAtlasRect;\n
+    uniform lowp vec4 uColor;\n
+    \n
+    void main()\n
+    {\n
+      mediump vec2 texCoord = mix( uAtlasRect.xy, uAtlasRect.zw, clamp( vTexCoord, 0.0, 1.0 ) );\n
+      gl_FragColor = texture2D( sTexture, texCoord ) * uColor;\n
+    }\n
+);
+
+const char* FRAGMENT_SHADER_ATLAS_VARIOUS_WRAP = DALI_COMPOSE_SHADER(
+    varying mediump vec2 vTexCoord;\n
+    uniform sampler2D sTexture;\n
+    uniform mediump vec4 uAtlasRect;\n
+    // WrapMode -- 0: CLAMP; 1: REPEAT; 2: REFLECT;
+    uniform lowp vec2 wrapMode;\n
+    uniform lowp vec4 uColor;\n
+    \n
+    mediump float wrapCoordinate( mediump float coordinate, lowp float wrap )\n
+    {\n
+      if( abs(wrap-2.0) < 0.5 )\n // REFLECT
+        return 1.0-abs(fract(coordinate*0.5)*2.0 - 1.0);\n
+      else \n// warp == 0 or 1
+        return mix( clamp( coordinate, 0.0, 1.0 ), fract( coordinate ), wrap);\n
+    }\n
+    void main()\n
+    {\n
+      mediump vec2 texCoord = mix( uAtlasRect.xy, uAtlasRect.zw,
+                              vec2( wrapCoordinate( vTexCoord.x, wrapMode.x ), wrapCoordinate( vTexCoord.y, wrapMode.y ) ) );\n
+      gl_FragColor = texture2D( sTexture, texCoord ) * uColor;\n
+    }\n
+);
+
 Geometry CreateGeometry( VisualFactoryCache& factoryCache, ImageDimensions gridSize )
 {
   Geometry geometry;
@@ -138,12 +184,14 @@ Geometry CreateGeometry( VisualFactoryCache& factoryCache, ImageDimensions gridS
 
 } //unnamed namespace
 
-ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, ImageAtlasManager& atlasManager )
+ImageVisual::ImageVisual( VisualFactoryCache& factoryCache )
 : Visual::Base( factoryCache ),
-  mAtlasManager( atlasManager ),
+  mPixelArea( FULL_TEXTURE_RECT ),
   mDesiredSize(),
   mFittingMode( FittingMode::DEFAULT ),
   mSamplingMode( SamplingMode::DEFAULT ),
+  mWrapModeU( WrapMode::DEFAULT ),
+  mWrapModeV( WrapMode::DEFAULT ),
   mNativeFragmentShaderCode( ),
   mNativeImageFlag( false )
 {
@@ -192,6 +240,24 @@ void ImageVisual::DoInitialize( Actor& actor, const Property::Map& propertyMap )
       desiredHeightValue->Get( desiredHeight );
     }
 
+    Property::Value* pixelAreaValue = propertyMap.Find( Toolkit::ImageVisual::Property::PIXEL_AREA, PIXEL_AREA_UNIFORM_NAME );
+    if( pixelAreaValue )
+    {
+      pixelAreaValue->Get( mPixelArea );
+    }
+
+    Property::Value* wrapModeValueU = propertyMap.Find( Toolkit::ImageVisual::Property::WRAP_MODE_U, IMAGE_WRAP_MODE_U );
+    if( wrapModeValueU )
+    {
+      Scripting::GetEnumerationProperty( *wrapModeValueU, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, mWrapModeU );
+    }
+
+    Property::Value* wrapModeValueV = propertyMap.Find( Toolkit::ImageVisual::Property::WRAP_MODE_V, IMAGE_WRAP_MODE_V );
+    if( wrapModeValueV )
+    {
+      Scripting::GetEnumerationProperty( *wrapModeValueV, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, mWrapModeV );
+    }
+
     mDesiredSize = ImageDimensions( desiredWidth, desiredHeight );
   }
 
@@ -244,11 +310,6 @@ void ImageVisual::DoInitialize( Actor& actor, const Property::Map& propertyMap )
   }
 }
 
-void ImageVisual::SetSize( const Vector2& size )
-{
-  Visual::Base::SetSize( size );
-}
-
 void ImageVisual::GetNaturalSize( Vector2& naturalSize ) const
 {
   if(mImage)
@@ -274,15 +335,6 @@ void ImageVisual::GetNaturalSize( Vector2& naturalSize ) const
   naturalSize = Vector2::ZERO;
 }
 
-void ImageVisual::SetClipRect( const Rect<int>& clipRect )
-{
-  Visual::Base::SetClipRect( clipRect );
-}
-
-void ImageVisual::SetOffset( const Vector2& offset )
-{
-}
-
 Renderer ImageVisual::CreateRenderer() const
 {
   Geometry geometry;
@@ -299,23 +351,24 @@ Renderer ImageVisual::CreateRenderer() const
   {
     geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
 
-    shader = GetImageShader(mFactoryCache);
+    shader = GetImageShader( mFactoryCache,
+                             mImpl->mFlags & Impl::IS_ATLASING_APPLIED,
+                             mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE );
   }
   else
   {
     geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
     if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() )
     {
-      shader = GetImageShader(mFactoryCache);
+      shader = GetImageShader(mFactoryCache, false, true);
     }
     else
     {
       shader  = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
-                             mImpl->mCustomShader->mFragmentShader.empty() ? FRAGMENT_SHADER : mImpl->mCustomShader->mFragmentShader,
+                             mImpl->mCustomShader->mFragmentShader.empty() ? FRAGMENT_SHADER_NO_ATLAS : mImpl->mCustomShader->mFragmentShader,
                              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 );
       }
     }
@@ -336,7 +389,6 @@ Renderer ImageVisual::CreateNativeImageRenderer() const
     geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
 
     shader  = Shader::New( VERTEX_SHADER, mNativeFragmentShaderCode );
-    shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
     shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
   }
   else
@@ -347,7 +399,6 @@ Renderer ImageVisual::CreateNativeImageRenderer() const
                            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 );
     }
   }
@@ -355,7 +406,6 @@ Renderer ImageVisual::CreateNativeImageRenderer() const
   TextureSet textureSet = TextureSet::New();
   Renderer renderer = Renderer::New( geometry, shader );
   renderer.SetTextures( textureSet );
-
   return renderer;
 }
 
@@ -382,7 +432,7 @@ Image ImageVisual::LoadImage( const std::string& url, bool synchronousLoading )
     if( !mPixels )
     {
       // use broken image
-      return VisualFactory::GetBrokenVisualImage();
+      return VisualFactoryCache::GetBrokenVisualImage();
     }
     Atlas image = Atlas::New( mPixels.GetWidth(), mPixels.GetHeight(), mPixels.GetPixelFormat() );
     image.Upload( mPixels, 0, 0 );
@@ -406,13 +456,15 @@ TextureSet ImageVisual::CreateTextureSet( Vector4& textureRect, const std::strin
     {
       // use broken image
       textureSet = TextureSet::New();
-      TextureSetImage( textureSet, 0u, VisualFactory::GetBrokenVisualImage() );
+      TextureSetImage( textureSet, 0u, VisualFactoryCache::GetBrokenVisualImage() );
     }
     else
     {
-      textureSet = mAtlasManager.Add(textureRect, mPixels );
+      textureSet = mFactoryCache.GetAtlasManager()->Add(textureRect, mPixels );
+      mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
       if( !textureSet ) // big image, no atlasing
       {
+        mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
         Atlas image = Atlas::New( mPixels.GetWidth(), mPixels.GetHeight(), mPixels.GetPixelFormat() );
         image.Upload( mPixels, 0, 0 );
         textureSet = TextureSet::New();
@@ -422,9 +474,11 @@ TextureSet ImageVisual::CreateTextureSet( Vector4& textureRect, const std::strin
   }
   else
   {
-    textureSet = mAtlasManager.Add(textureRect, url, mDesiredSize, mFittingMode, mSamplingMode );
+    textureSet = mFactoryCache.GetAtlasManager()->Add(textureRect, url, mDesiredSize, mFittingMode, true, this );
+    mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
     if( !textureSet ) // big image, no atlasing
     {
+      mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
       ResourceImage resourceImage = Dali::ResourceImage::New( url, mDesiredSize, mFittingMode, mSamplingMode );
       resourceImage.LoadingFinishedSignal().Connect( this, &ImageVisual::OnImageLoaded );
       textureSet = TextureSet::New();
@@ -432,6 +486,13 @@ TextureSet ImageVisual::CreateTextureSet( Vector4& textureRect, const std::strin
     }
   }
 
+  if( !(mImpl->mFlags & Impl::IS_ATLASING_APPLIED) )
+  {
+    Sampler sampler = Sampler::New();
+    sampler.SetWrapMode(  mWrapModeU, mWrapModeV  );
+    textureSet.SetSampler( 0u, sampler );
+  }
+
   return textureSet;
 }
 
@@ -444,33 +505,52 @@ void ImageVisual::InitializeRenderer( const std::string& imageUrl )
 
   mImageUrl = imageUrl;
   mImpl->mRenderer.Reset();
+  mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
 
   if( !mImpl->mCustomShader &&
       ( strncasecmp( imageUrl.c_str(), HTTP_URL,  sizeof(HTTP_URL)  -1 ) != 0 ) && // ignore remote images
       ( strncasecmp( imageUrl.c_str(), HTTPS_URL, sizeof(HTTPS_URL) -1 ) != 0 ) )
   {
-    mImpl->mRenderer = mFactoryCache.GetRenderer( imageUrl );
-    if( !mImpl->mRenderer )
+    bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
+    bool cacheable =  defaultWrapMode &&  mPixelArea == FULL_TEXTURE_RECT;
+
+    mImpl->mFlags &= ~Impl::IS_FROM_CACHE;
+    if( cacheable ) // fetch the renderer from cache if exist
+    {
+      mImpl->mRenderer = mFactoryCache.GetRenderer( imageUrl );
+      mImpl->mFlags |= Impl::IS_FROM_CACHE;
+    }
+
+    if( !mImpl->mRenderer ) // new renderer is needed
     {
       Vector4 atlasRect;
       TextureSet textureSet = CreateTextureSet(atlasRect, imageUrl, IsSynchronousResourceLoading() );
       Geometry geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
-      Shader shader( GetImageShader(mFactoryCache) );
+      Shader shader( GetImageShader(mFactoryCache, mImpl->mFlags & Impl::IS_ATLASING_APPLIED, defaultWrapMode) );
       mImpl->mRenderer = Renderer::New( geometry, shader );
       mImpl->mRenderer.SetTextures( textureSet );
-      if( atlasRect != FULL_TEXTURE_RECT )
+
+      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, renderer is not cached.
+        {
+          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 );
+        }
       }
-      mFactoryCache.SaveRenderer( imageUrl, mImpl->mRenderer );
-    }
 
-    mImpl->mFlags |= Impl::IS_FROM_CACHE;
+      // save the renderer to cache only when default wrap mode and default pixel area is used
+      if( cacheable )
+      {
+        mFactoryCache.SaveRenderer( imageUrl, mImpl->mRenderer );
+      }
+    }
   }
   else
   {
     // for custom shader or remote image, renderer is not cached and atlas is not applied
-
     mImpl->mFlags &= ~Impl::IS_FROM_CACHE;
     mImpl->mRenderer = CreateRenderer();
     Image image = LoadImage( imageUrl, IsSynchronousResourceLoading() );
@@ -488,11 +568,30 @@ void ImageVisual::InitializeRenderer( const Image& image )
   {
     ApplyImageToSampler( image );
   }
+
+  if( mPixelArea != FULL_TEXTURE_RECT )
+  {
+    mImpl->mRenderer.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, mPixelArea );
+  }
 }
 
 
+void ImageVisual::UploadCompleted()
+{
+  // Resource image is loaded. If weak handle is holding a placement actor, it is the time to add the renderer to actor.
+  Actor actor = mPlacementActor.GetHandle();
+  if( actor )
+  {
+    actor.AddRenderer( mImpl->mRenderer );
+    // reset the weak handle so that the renderer only get added to actor once
+    mPlacementActor.Reset();
+  }
+}
+
 void ImageVisual::DoSetOnStage( Actor& actor )
 {
+  mPlacementActor = actor;
+
   if( !mImageUrl.empty() )
   {
     InitializeRenderer( mImageUrl );
@@ -502,7 +601,11 @@ void ImageVisual::DoSetOnStage( Actor& actor )
     InitializeRenderer( mImage );
   }
 
-  actor.AddRenderer( mImpl->mRenderer );
+  if( IsSynchronousResourceLoading() || !(mImpl->mFlags & Impl::IS_ATLASING_APPLIED) )
+  {
+    actor.AddRenderer( mImpl->mRenderer );
+    mPlacementActor.Reset();
+  }
 }
 
 void ImageVisual::DoSetOffStage( Actor& actor )
@@ -519,6 +622,7 @@ void ImageVisual::DoSetOffStage( Actor& actor )
     actor.RemoveRenderer( mImpl->mRenderer );
     mImpl->mRenderer.Reset();
   }
+  mPlacementActor.Reset();
 }
 
 void ImageVisual::DoCreatePropertyMap( Property::Map& map ) const
@@ -548,18 +652,46 @@ void ImageVisual::DoCreatePropertyMap( Property::Map& map ) const
 
   map.Insert( Toolkit::ImageVisual::Property::FITTING_MODE, mFittingMode );
   map.Insert( Toolkit::ImageVisual::Property::SAMPLING_MODE, mSamplingMode );
+
+  map.Insert( Toolkit::ImageVisual::Property::PIXEL_AREA, mPixelArea );
+  map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_U, mWrapModeU );
+  map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV );
 }
 
-Shader ImageVisual::GetImageShader( VisualFactoryCache& factoryCache )
+Shader ImageVisual::GetImageShader( VisualFactoryCache& factoryCache, bool atlasing, bool defaultTextureWrapping )
 {
-  Shader shader = factoryCache.GetShader( VisualFactoryCache::IMAGE_SHADER );
-  if( !shader )
+  Shader shader;
+  if( atlasing )
   {
-    shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
-    factoryCache.SaveShader( VisualFactoryCache::IMAGE_SHADER, shader );
-    shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
-    shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+    if( defaultTextureWrapping )
+    {
+      shader = factoryCache.GetShader( VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP );
+      if( !shader )
+      {
+        shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ATLAS_CLAMP );
+        factoryCache.SaveShader( VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP, shader );
+      }
+    }
+    else
+    {
+      shader = factoryCache.GetShader( VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP );
+      if( !shader )
+      {
+        shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ATLAS_VARIOUS_WRAP );
+        factoryCache.SaveShader( VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP, shader );
+      }
+    }
+  }
+  else
+  {
+    shader = factoryCache.GetShader( VisualFactoryCache::IMAGE_SHADER );
+    if( !shader )
+    {
+      shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_NO_ATLAS );
+      factoryCache.SaveShader( VisualFactoryCache::IMAGE_SHADER, shader );
+    }
   }
+  shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
   return shader;
 }
 
@@ -699,6 +831,9 @@ void ImageVisual::ApplyImageToSampler( const Image& image )
       mImpl->mRenderer.SetTextures( textureSet );
     }
     TextureSetImage( textureSet, 0u, image );
+    Sampler sampler = Sampler::New();
+    sampler.SetWrapMode(  mWrapModeU, mWrapModeV  );
+    textureSet.SetSampler( 0u, sampler );
   }
 }
 
@@ -706,7 +841,7 @@ void ImageVisual::OnImageLoaded( ResourceImage image )
 {
   if( image.GetLoadingState() == Dali::ResourceLoadingFailed )
   {
-    Image brokenImage = VisualFactory::GetBrokenVisualImage();
+    Image brokenImage = VisualFactoryCache::GetBrokenVisualImage();
     if( mImpl->mRenderer )
     {
       ApplyImageToSampler( brokenImage );
@@ -729,7 +864,7 @@ void ImageVisual::CleanCache(const std::string& url)
   mImpl->mRenderer.Reset();
   if( mFactoryCache.CleanRendererCache( url ) && index != Property::INVALID_INDEX )
   {
-    mAtlasManager.Remove( textureSet, atlasRect );
+    mFactoryCache.GetAtlasManager()->Remove( textureSet, atlasRect );
   }
 }
 
@@ -750,7 +885,7 @@ void ImageVisual::SetNativeFragmentShaderCode( Dali::NativeImage& nativeImage )
   }
   else
   {
-    mNativeFragmentShaderCode += FRAGMENT_SHADER;
+    mNativeFragmentShaderCode += FRAGMENT_SHADER_NO_ATLAS;
   }
 
   if( customSamplerTypename )
index 57c7016..d6947e3 100644 (file)
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
-#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
+#include <dali-toolkit/devel-api/image-loader/atlas-upload-observer.h>
 
 // EXTERNAL INCLUDES
 #include <dali/public-api/images/image.h>
 #include <dali/public-api/images/image-operations.h>
 #include <dali/public-api/images/resource-image.h>
+#include <dali/devel-api/object/weak-handle.h>
 
 namespace Dali
 {
@@ -73,7 +74,7 @@ typedef IntrusivePtr< ImageVisual > ImageVisualPtr;
  *   "DEFAULT"
  *
  */
-class ImageVisual: public Visual::Base, public ConnectionTracker
+class ImageVisual: public Visual::Base, public ConnectionTracker, public AtlasUploadObserver
 {
 public:
 
@@ -81,9 +82,8 @@ public:
    * @brief Constructor.
    *
    * @param[in] factoryCache The VisualFactoryCache object
-   * @param[in] atlasManager The atlasManager object
    */
-  ImageVisual( VisualFactoryCache& factoryCache, ImageAtlasManager& atlasManager );
+  ImageVisual( VisualFactoryCache& factoryCache );
 
   /**
    * @brief A reference counted object may only be deleted by calling Unreference().
@@ -93,27 +93,12 @@ public:
 public:  // from Visual
 
   /**
-   * @copydoc Visual::Base::SetSize
-   */
-  virtual void SetSize( const Vector2& size );
-
-  /**
-   * @copydoc Visual::Base::GetNaturalSize
+   * @copydoc Visual::GetNaturalSize
    */
   virtual void GetNaturalSize( Vector2& naturalSize ) const;
 
   /**
-   * @copydoc Visual::Base::SetClipRect
-   */
-  virtual void SetClipRect( const Rect<int>& clipRect );
-
-  /**
-   * @copydoc Visual::Base::SetOffset
-   */
-  virtual void SetOffset( const Vector2& offset );
-
-  /**
-   * @copydoc Visual::Base::CreatePropertyMap
+   * @copydoc Visual::CreatePropertyMap
    */
   virtual void DoCreatePropertyMap( Property::Map& map ) const;
 
@@ -138,8 +123,10 @@ public:
   /**
    * Get the standard image rendering shader.
    * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] atlasing Whether texture atlasing is applied.
+   * @param[in] defaultTextureWrapping Whether the default texture wrap mode is applied.
    */
-  static Shader GetImageShader( VisualFactoryCache& factoryCache );
+  static Shader GetImageShader( VisualFactoryCache& factoryCache, bool atlasing, bool defaultTextureWrapping );
 
   /**
    * @brief Sets the image of this visual to the resource at imageUrl
@@ -165,6 +152,14 @@ public:
    */
   void SetImage( Actor& actor, const Image& image );
 
+  /**
+   * @copydoc AtlasUploadObserver::UploadCompleted
+   *
+   * To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready.
+   * This callback is the place to add the renderer as it would be called once the loading is finished.
+   */
+  virtual void UploadCompleted();
+
 private:
 
   /**
@@ -252,13 +247,16 @@ private:
 
 private:
   Image mImage;
-  ImageAtlasManager& mAtlasManager;
   PixelData mPixels;
+  Vector4 mPixelArea;
+  WeakHandle<Actor> mPlacementActor;
 
   std::string mImageUrl;
   Dali::ImageDimensions mDesiredSize;
   Dali::FittingMode::Type mFittingMode;
   Dali::SamplingMode::Type mSamplingMode;
+  Dali::WrapMode::Type mWrapModeU;
+  Dali::WrapMode::Type mWrapModeV;
 
   std::string mNativeFragmentShaderCode;
   bool mNativeImageFlag;
index 56a75e5..af36fb7 100644 (file)
@@ -524,7 +524,7 @@ void NPatchVisual::InitializeFromImage( NinePatchImage nPatch )
 
 void NPatchVisual::InitializeFromBrokenImage()
 {
-  mCroppedImage = VisualFactory::GetBrokenVisualImage();
+  mCroppedImage = VisualFactoryCache::GetBrokenVisualImage();
   mImageSize = ImageDimensions( mCroppedImage.GetWidth(), mCroppedImage.GetHeight() );
 
   mStretchPixelsX.Clear();
index 2d6a263..f1658f1 100644 (file)
@@ -31,6 +31,7 @@
 #include <dali-toolkit/third-party/nanosvg/nanosvg.h>
 #include <dali-toolkit/internal/visuals/svg/svg-rasterize-thread.h>
 #include <dali-toolkit/internal/visuals/image/image-visual.h>
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
@@ -52,10 +53,9 @@ namespace Toolkit
 namespace Internal
 {
 
-SvgVisual::SvgVisual( VisualFactoryCache& factoryCache, ImageAtlasManager& atlasManager )
+SvgVisual::SvgVisual( VisualFactoryCache& factoryCache )
 : Visual::Base( factoryCache ),
   mAtlasRect( FULL_TEXTURE_RECT ),
-  mAtlasManager( atlasManager ),
   mParsedImage( NULL )
 {
   // the rasterized image is with pre-multiplied alpha format
@@ -94,7 +94,7 @@ void SvgVisual::DoInitialize( Actor& actor, const Property::Map& propertyMap )
 
 void SvgVisual::DoSetOnStage( Actor& actor )
 {
-  Shader shader = ImageVisual::GetImageShader( mFactoryCache );
+  Shader shader = ImageVisual::GetImageShader( mFactoryCache, true, true );
   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
   if( !geometry )
   {
@@ -202,11 +202,11 @@ void SvgVisual::ApplyRasterizedImage( PixelData rasterizedPixelData )
     TextureSet currentTextureSet = mImpl->mRenderer.GetTextures();
     if( mAtlasRect != FULL_TEXTURE_RECT )
     {
-      mAtlasManager.Remove( currentTextureSet, mAtlasRect );
+      mFactoryCache.GetAtlasManager()->Remove( currentTextureSet, mAtlasRect );
     }
 
     Vector4 atlasRect;
-    TextureSet textureSet = mAtlasManager.Add(atlasRect, rasterizedPixelData );
+    TextureSet textureSet = mFactoryCache.GetAtlasManager()->Add(atlasRect, rasterizedPixelData );
     if( textureSet ) // atlasing
     {
       if( textureSet != currentTextureSet )
@@ -215,11 +215,13 @@ void SvgVisual::ApplyRasterizedImage( PixelData rasterizedPixelData )
       }
       mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, atlasRect );
       mAtlasRect = atlasRect;
+      mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
     }
     else // no atlasing
     {
       Atlas texture = Atlas::New( rasterizedPixelData.GetWidth(), rasterizedPixelData.GetHeight() );
       texture.Upload( rasterizedPixelData, 0, 0 );
+      mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
 
       if( mAtlasRect == FULL_TEXTURE_RECT )
       {
index 70d4bd4..4fc6030 100644 (file)
@@ -23,7 +23,6 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
-#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
 
 struct NSVGimage;
 
@@ -55,7 +54,7 @@ public:
    *
    * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
    */
-  SvgVisual( VisualFactoryCache& factoryCache, ImageAtlasManager& atlasManager );
+  SvgVisual( VisualFactoryCache& factoryCache );
 
   /**
    * @brief A reference counted object may only be deleted by calling Unreference().
@@ -139,7 +138,6 @@ private:
 
 private:
   Vector4              mAtlasRect;
-  ImageAtlasManager&   mAtlasManager;
   std::string          mImageUrl;
   NSVGimage*           mParsedImage;
   WeakHandle<Actor>    mPlacementActor;
index 3ffdafb..fb8ae32 100644 (file)
@@ -43,8 +43,9 @@ struct Base::Impl
   {
     IS_ON_STAGE = 1,
     IS_FROM_CACHE = 1 << 1,
-    IS_PREMULTIPLIED_ALPHA = 1 << 2,
-    IS_SYNCHRONOUS_RESOURCE_LOADING = 1 << 3
+    IS_ATLASING_APPLIED = 1<<2,
+    IS_PREMULTIPLIED_ALPHA = 1 << 3,
+    IS_SYNCHRONOUS_RESOURCE_LOADING = 1 << 4
   };
 
   struct CustomShader
index b3f8ab6..207a840 100644 (file)
 
 // EXTERNAL HEADER
 #include <dali/devel-api/common/hash.h>
+#include <dali/public-api/images/resource-image.h>
 
 // INTERNAL HEADER
 #include <dali-toolkit/internal/visuals/color/color-visual.h>
 #include <dali-toolkit/internal/visuals/svg/svg-visual.h>
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
+
+namespace
+{
+const char * const BROKEN_VISUAL_IMAGE_URL( DALI_IMAGE_DIR "broken.png");
+}
 
 namespace Dali
 {
@@ -179,6 +186,17 @@ Geometry VisualFactoryCache::CreateQuadGeometry()
   return geometry;
 }
 
+ImageAtlasManagerPtr VisualFactoryCache::GetAtlasManager()
+{
+  if( !mAtlasManager )
+  {
+    mAtlasManager = new ImageAtlasManager();
+    mAtlasManager->SetBrokenImage( BROKEN_VISUAL_IMAGE_URL );
+  }
+
+  return mAtlasManager;
+}
+
 SvgRasterizeThread* VisualFactoryCache::GetSVGRasterizationThread()
 {
   if( !mSvgRasterizeThread )
@@ -266,6 +284,11 @@ Geometry VisualFactoryCache::CreateGridGeometry( Uint16Pair gridSize )
   return geometry;
 }
 
+Image VisualFactoryCache::GetBrokenVisualImage()
+{
+  return ResourceImage::New( BROKEN_VISUAL_IMAGE_URL );
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index 232495d..4eb56e8 100644 (file)
@@ -39,6 +39,9 @@ namespace Toolkit
 namespace Internal
 {
 
+class ImageAtlasManager;
+typedef IntrusivePtr<ImageAtlasManager> ImageAtlasManagerPtr;
+
 /**
  * Caches shaders and geometries. Owned by VisualFactory.
  */
@@ -59,6 +62,8 @@ public:
     GRADIENT_SHADER_RADIAL_USER_SPACE,
     GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
     IMAGE_SHADER,
+    IMAGE_SHADER_ATLAS_DEFAULT_WRAP,
+    IMAGE_SHADER_ATLAS_CUSTOM_WRAP,
     NINE_PATCH_SHADER,
     SVG_SHADER,
     SHADER_TYPE_MAX = SVG_SHADER
@@ -122,6 +127,12 @@ public:
    */
   static Geometry CreateGridGeometry( Uint16Pair gridSize );
 
+  /**
+   * @brief Returns an image to be used when a visual has failed to correctly render
+   * @return The broken image handle.
+   */
+  static Image GetBrokenVisualImage();
+
 public:
 
   /**
@@ -162,6 +173,12 @@ public:
   Renderer GetWireframeRenderer();
 
   /**
+   * Get the image atlas manager.
+   * @return A pointer pointing to the atlas manager
+   */
+  ImageAtlasManagerPtr GetAtlasManager();
+
+  /**
    * Get the SVG rasterization thread.
    * @return A pointer pointing to the SVG rasterization thread.
    */
@@ -222,6 +239,7 @@ private:
 
   Renderer mWireframeRenderer;
 
+  ImageAtlasManagerPtr mAtlasManager;
   SvgRasterizeThread*  mSvgRasterizeThread;
 };
 
index 71152d9..c1bd457 100644 (file)
 #include <dali-toolkit/internal/visuals/wireframe/wireframe-visual.h>
 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
 
-namespace
-{
-const char * const BROKEN_VISUAL_IMAGE_URL( DALI_IMAGE_DIR "broken.png");
-}
 namespace Dali
 {
 
@@ -144,20 +140,16 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property
         {
           visualPtr = new NPatchVisual( *( mFactoryCache.Get() ) );
         }
+        else if( SvgVisual::IsSvgUrl( imageUrl ) )
+        {
+          visualPtr = new SvgVisual( *( mFactoryCache.Get() ) );
+        }
         else
         {
-          CreateAtlasManager();
-
-          if( SvgVisual::IsSvgUrl( imageUrl ) )
-          {
-            visualPtr = new SvgVisual( *( mFactoryCache.Get() ), *( mAtlasManager.Get() ) );
-          }
-          else
-          {
-            visualPtr = new ImageVisual( *( mFactoryCache.Get() ), *( mAtlasManager.Get() ) );
-          }
+          visualPtr = new ImageVisual( *( mFactoryCache.Get() ) );
         }
       }
+
       break;
     }
 
@@ -215,8 +207,7 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Image& image )
   }
   else
   {
-    CreateAtlasManager();
-    ImageVisual* visualPtr = new ImageVisual( *( mFactoryCache.Get() ), *( mAtlasManager.Get() ) );
+    ImageVisual* visualPtr = new ImageVisual( *( mFactoryCache.Get() ) );
     Actor actor;
     visualPtr->SetImage( actor, image );
 
@@ -245,15 +236,13 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const std::string& url, Image
   }
   else if( SvgVisual::IsSvgUrl( url ) )
   {
-    CreateAtlasManager();
-    SvgVisual* visualPtr = new SvgVisual( *( mFactoryCache.Get() ), *( mAtlasManager.Get() ) );
+    SvgVisual* visualPtr = new SvgVisual( *( mFactoryCache.Get() ) );
     visualPtr->SetImage( url, size );
     return Toolkit::Visual::Base( visualPtr );
   }
   else
   {
-    CreateAtlasManager();
-    ImageVisual* visualPtr = new ImageVisual( *( mFactoryCache.Get() ), *( mAtlasManager.Get() ) );
+    ImageVisual* visualPtr = new ImageVisual( *( mFactoryCache.Get() ));
     Actor actor;
     visualPtr->SetImage( actor, url, size );
 
@@ -261,21 +250,6 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const std::string& url, Image
   }
 }
 
-Image VisualFactory::GetBrokenVisualImage()
-{
-  return ResourceImage::New( BROKEN_VISUAL_IMAGE_URL );
-}
-
-void VisualFactory::CreateAtlasManager()
-{
-  if( !mAtlasManager )
-  {
-    Shader shader = ImageVisual::GetImageShader( *( mFactoryCache.Get() ) );
-    mAtlasManager = new ImageAtlasManager();
-    mAtlasManager->SetBrokenImage( BROKEN_VISUAL_IMAGE_URL );
-  }
-}
-
 } // namespace Internal
 
 } // namespace Toolkit
index f6e8d9c..484a688 100644 (file)
@@ -36,9 +36,6 @@ namespace Internal
 class VisualFactoryCache;
 typedef IntrusivePtr<VisualFactoryCache> VisualFactoryCachePtr;
 
-class ImageAtlasManager;
-typedef IntrusivePtr<ImageAtlasManager> ImageAtlasManagerPtr;
-
 /**
  * @copydoc Toolkit::VisualFactory
  */
@@ -68,11 +65,6 @@ public:
    */
   Toolkit::Visual::Base CreateVisual( const std::string& image, ImageDimensions size );
 
-public:
-  /**
-   * @brief Returns an image to be used when a visual has failed to correctly render
-   */
-  static Image GetBrokenVisualImage();
 
 protected:
 
@@ -84,11 +76,6 @@ protected:
 private:
 
   /**
-   * Prepare the atlas manager
-   */
-  void CreateAtlasManager();
-
-  /**
    * Undefined copy constructor.
    */
   VisualFactory(const VisualFactory&);
@@ -101,7 +88,6 @@ private:
 private:
 
   VisualFactoryCachePtr   mFactoryCache;
-  ImageAtlasManagerPtr    mAtlasManager;
   bool                    mDebugEnabled;
 };
 
index de5e006..c8276e2 100755 (executable)
@@ -25,6 +25,8 @@ public_api_src_files = \
   $(public_api_src_dir)/controls/text-controls/text-editor.cpp \
   $(public_api_src_dir)/controls/text-controls/text-label.cpp \
   $(public_api_src_dir)/controls/text-controls/text-field.cpp \
+  $(public_api_src_dir)/image-loader/async-image-loader.cpp \
+  $(public_api_src_dir)/image-loader/sync-image-loader.cpp \
   $(public_api_src_dir)/styling/style-manager.cpp \
   $(public_api_src_dir)/accessibility-manager/accessibility-manager.cpp \
   $(public_api_src_dir)/focus-manager/keyboard-focus-manager.cpp \
@@ -68,6 +70,10 @@ public_api_item_view_header_files = \
   $(public_api_src_dir)/controls/scrollable/item-view/item-view-declarations.h \
   $(public_api_src_dir)/controls/scrollable/item-view/item-view.h
 
+public_api_image_loader_header_files = \
+  $(public_api_src_dir)/image-loader/async-image-loader.h \
+  $(public_api_src_dir)/image-loader/sync-image-loader.h
+
 public_api_scrollable_header_files = \
   $(public_api_src_dir)/controls/scrollable/scrollable.h
 
diff --git a/dali-toolkit/public-api/image-loader/async-image-loader.cpp b/dali-toolkit/public-api/image-loader/async-image-loader.cpp
new file mode 100644 (file)
index 0000000..c1e23ee
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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::DownCast( BaseHandle handle )
+{
+  return AsyncImageLoader( dynamic_cast<Dali::Toolkit::Internal::AsyncImageLoader*>( handle.GetObjectPtr() ) );
+}
+
+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 dimensions )
+{
+  return GetImplementation( *this ).Load( url, dimensions, FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true );
+}
+
+uint32_t AsyncImageLoader::Load( const std::string& url,
+                                 ImageDimensions dimensions,
+                                 FittingMode::Type fittingMode,
+                                 SamplingMode::Type samplingMode,
+                                 bool orientationCorrection )
+{
+  return GetImplementation(*this).Load( url, dimensions, 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/public-api/image-loader/async-image-loader.h b/dali-toolkit/public-api/image-loader/async-image-loader.h
new file mode 100644 (file)
index 0000000..844d758
--- /dev/null
@@ -0,0 +1,245 @@
+#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 AsyncImageLoader is used to load pixel data from a URL asynchronously.
+ *
+ * The images are loaded in a worker thread to avoid blocking the main event thread.
+ *
+ * To keep track of the loading images, each load call is assigned an ID (which is returned by the Load() call).
+ * To know when the Load has completed, connect to the ImageLoadedSignal.
+ * This signal should be connected before Load is called (in case the signal is emitted immediately).
+ *
+ * Load errors can be detected by checking the PixelData object is valid from within the signal handler.
+
+ * Note: The PixelData object will automatically be destroyed when it leaves its scope.
+ *
+ * Example:
+ *
+ * @code
+ * class MyClass : public ConnectionTracker
+ * {
+ *   public:
+ *
+ *   MyCallback( uint32_t loadedTaskId, PixelData pixelData )
+ *   {
+ *     // First check if the image loaded correctly.
+ *     if( pixelData )
+ *     {
+ *       if( loadedTaskId == mId1 )
+ *       {
+ *         // use the loaded pixel data from the first image
+ *       }
+ *       else if( loadedTaskId == 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 );
+ *
+ * // Invoke the load calls (must do this after connecting the signal to guarantee callbacks occur).
+ * myObject.mId1 = imageLoader.Load( "first_image_url.jpg" );
+ * myObject.mId2 = imageLoader.Load( "second_image_url.jpg" );
+ *
+ * @endcode
+ */
+class DALI_IMPORT_API AsyncImageLoader : public BaseHandle
+{
+public:
+
+  typedef Signal< void( uint32_t, PixelData ) > ImageLoadedSignalType; ///< Image loaded signal type @SINCE_1_2_14
+
+public:
+
+  /**
+   * @brief Constructor which creates an empty AsyncImageLoader handle.
+   * @SINCE_1_2_14
+   *
+   * Use AsyncImageLoader::New() to create an initialised object.
+   */
+  AsyncImageLoader();
+
+  /**
+   * @brief Destructor
+   * @SINCE_1_2_14
+   *
+   * 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.
+   * @SINCE_1_2_14
+   *
+   * @param[in] handle A reference to the copied handle
+   */
+  AsyncImageLoader( const AsyncImageLoader& handle );
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   * @SINCE_1_2_14
+   *
+   * @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.
+   * @SINCE_1_2_14
+   *
+   * @return The image loader.
+   */
+  static AsyncImageLoader New();
+
+  /**
+   * @brief Downcast a handle to AsyncImageLoader handle.
+   *
+   * If the handle points to an AsyncImageLoader object the downcast produces
+   * a valid handle. If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_1_2_14
+   * @param[in] handle A handle to an object
+   * @return A handle to a AsyncImageLoader object or an uninitialized handle
+   */
+  static AsyncImageLoader DownCast( BaseHandle handle );
+
+  /**
+   * @brief Start an image loading task.
+   * Note: When using this method, the following defaults will be used:
+   * fittingMode = FittingMode::DEFAULT
+   * samplingMode = SamplingMode::BOX_THEN_LINEAR
+   * orientationCorrection = true
+   *
+   * @SINCE_1_2_14
+   *
+   * @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 an image loading task.
+   * Note: When using this method, the following defaults will be used:
+   * fittingMode = FittingMode::DEFAULT
+   * samplingMode = SamplingMode::BOX_THEN_LINEAR
+   * orientationCorrection = true
+   *
+   * @SINCE_1_2_14
+   *
+   * @param[in] url The URL of the image file to load.
+   * @param[in] dimensions The width and height to fit the loaded image to.
+   * @return The loading task id.
+   */
+  uint32_t Load( const std::string& url, ImageDimensions dimensions );
+
+  /**
+   * @brief Start an image loading task.
+   * @SINCE_1_2_14
+   *
+   * @param[in] url The URL of the image file to load.
+   * @param[in] dimensions 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 dimensions,
+                 FittingMode::Type fittingMode,
+                 SamplingMode::Type samplingMode,
+                 bool orientationCorrection );
+
+  /**
+   * @brief Cancel a image loading task if it is still queueing in the work thread.
+   * @SINCE_1_2_14
+   *
+   * @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
+   * @SINCE_1_2_14
+   */
+  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
+   * @SINCE_1_2_14
+   *
+   * @return A reference to a signal object to Connect() with.
+   */
+  ImageLoadedSignalType& ImageLoadedSignal();
+
+public: // Not intended for developer use
+
+  /// @cond internal
+  /**
+   * @brief Allows the creation of a AsyncImageLoader handle from an internal pointer.
+   *
+   * @note Not intended for application developers
+   * @SINCE_1_2_14
+   *
+   * @param[in] impl A pointer to the object.
+   */
+  explicit DALI_INTERNAL AsyncImageLoader( Internal::AsyncImageLoader* impl );
+  /// @endcond
+
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ASYNC_IMAGE_LOADER_H
diff --git a/dali-toolkit/public-api/image-loader/sync-image-loader.cpp b/dali-toolkit/public-api/image-loader/sync-image-loader.cpp
new file mode 100644 (file)
index 0000000..de489dc
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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 "sync-image-loader.h"
+#include <dali/devel-api/adaptor-framework/bitmap-loader.h>
+
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace SyncImageLoader
+{
+
+
+PixelData Load( const std::string& url )
+{
+  return Load( url, ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true );
+}
+
+PixelData Load( const std::string& url, ImageDimensions dimensions )
+{
+  return Load( url, dimensions, FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true );
+}
+
+PixelData Load( const std::string& url,
+                ImageDimensions dimensions,
+                FittingMode::Type fittingMode,
+                SamplingMode::Type samplingMode,
+                bool orientationCorrection )
+{
+  BitmapLoader loader = BitmapLoader::New( url, dimensions, fittingMode, samplingMode, orientationCorrection );
+
+  // Load the image synchronously (block the thread here).
+  loader.Load();
+
+  return loader.GetPixelData();
+}
+
+
+} // namespace SyncImageLoader
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/image-loader/sync-image-loader.h b/dali-toolkit/public-api/image-loader/sync-image-loader.h
new file mode 100644 (file)
index 0000000..1586218
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef DALI_TOOLKIT_SYNC_IMAGE_LOADER_H
+#define DALI_TOOLKIT_SYNC_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/images/image-operations.h>
+#include <dali/public-api/images/pixel-data.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace SyncImageLoader
+{
+
+/**
+ * @brief The methods in the SyncImageLoader namespace are used to load pixel data from a URL synchronously.
+ *
+ * Example:
+ *
+ * @code
+ * PixelData pixelData = Toolkit::SyncImageLoader::Load( "image_url.jpg" );
+ *
+ * // Check the image was loaded without error.
+ * if( pixelData )
+ * {
+ *   // Do work...
+ * }
+ *
+ * @endcode
+ */
+
+/**
+ * @brief Load an image synchronously.
+ * Note: When using this method, the following defaults will be used:
+ * fittingMode = FittingMode::DEFAULT
+ * samplingMode = SamplingMode::BOX_THEN_LINEAR
+ * orientationCorrection = true
+ *
+ * @SINCE_1_2_14
+ *
+ * @param[in] url The URL of the image file to load.
+ * @return A PixelData object containing the image, or an invalid object on failure.
+ */
+DALI_IMPORT_API PixelData Load( const std::string& url );
+
+/**
+ * @brief Load an image synchronously by specifying the target dimensions.
+ * Note: When using this method, the following defaults will be used:
+ * fittingMode = FittingMode::DEFAULT
+ * samplingMode = SamplingMode::BOX_THEN_LINEAR
+ * orientationCorrection = true
+ *
+ * @SINCE_1_2_14
+ *
+ * @param[in] url The URL of the image file to load.
+ * @param[in] dimensions The width and height to fit the loaded image to.
+ * @return A PixelData object containing the image, or an invalid object on failure.
+ */
+DALI_IMPORT_API PixelData Load( const std::string& url, ImageDimensions dimensions );
+
+/**
+ * @brief Load an image synchronously by specifying the target dimensions and options.
+ * @SINCE_1_2_14
+ *
+ * @param[in] url The URL of the image file to load.
+ * @param[in] dimensions 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 A PixelData object containing the image, or an invalid object on failure.
+ */
+DALI_IMPORT_API PixelData Load( const std::string& url,
+                ImageDimensions dimensions,
+                FittingMode::Type fittingMode,
+                SamplingMode::Type samplingMode,
+                bool orientationCorrection );
+
+} // namespace SyncImageLoader
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_SYNC_IMAGE_LOADER_H
index 619a8f1..f8f238c 100644 (file)
@@ -98,6 +98,37 @@ enum
    * @note For N-Patch images only.
    */
   BORDER_ONLY,
+
+  /**
+   * @brief The image area to be displayed.
+   * @details Name "pixelArea", type Property::VECTOR4.
+   *          It is a rectangular area.
+   *          The first two elements indicate the top-left position of the area, and the last two elements are the area width and height respectively.
+   * @SINCE_1_2.1
+   * @note Optional. If not specified, the default value is [0.0, 0.0, 1.0, 1.0], i.e. the entire area of the image.
+   * @note For Normal Quad images only.
+   */
+  PIXEL_AREA,
+
+  /**
+   * @brief The wrap mode for u coordinate.
+   * @details Name "wrapModeU", type Dali::WrapMode::Type (Property::INTEGER) or Property::STRING
+   *          It decides how the texture should be sampled when the u coordinate exceeds the range of 0.0 to 1.0.
+   * @SINCE_1_2.1
+   * @note Optional. If not specified, the default is CLAMP.
+   * @note For Normal QUAD image only.
+   */
+  WRAP_MODE_U,
+
+  /**
+   * @brief The wrap mode for v coordinate.
+   * @details Name "wrapModeV", type Dali::WrapMode::Type (Property::INTEGER) or Property::STRING
+   *          it decides how the texture should be sampled when the v coordinate exceeds the range of 0.0 to 1.0.
+   * @SINCE_1_2.1
+   * @note Optional. If not specified, the default is CLAMP.
+   * @note For Normal QUAD image only.
+   */
+  WRAP_MODE_V,
 };
 
 } // namespace Property