Implement some cases for ExternalTexture usage 35/315535/12
authorEunki Hong <eunkiki.hong@samsung.com>
Mon, 11 Dec 2023 11:54:50 +0000 (20:54 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Thu, 19 Dec 2024 02:16:04 +0000 (11:16 +0900)
 - Support external texture as input of masking
 - Make already cached masking input for external texture works well
 - Make fail to load masking input for external texture works well
 - Ignore RELOAD action for external texture
 - Allow to support AnimatedImageVisual with ExternalTexture and Buffer
 - Load with external texture create another texture id
 - (Extra) Cache masking image and for AnimatedImageVisual case
 - (Extra) Move external resource reference control codes to VisualUrl

Furthermore, let we make good utility to convert from location to
TextureId at VisualUrl.

TODO : Some UTC crashed after cache sync loaded AnimatedImageVisual result.
We should fix it soon.

Change-Id: I7f45255a33af280b2e57e589fda7b294eb660465
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
13 files changed:
automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-VisualUrl.cpp
automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp
dali-toolkit/internal/texture-manager/texture-cache-manager.cpp
dali-toolkit/internal/texture-manager/texture-cache-manager.h
dali-toolkit/internal/texture-manager/texture-manager-impl.cpp
dali-toolkit/internal/texture-manager/texture-manager-impl.h
dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/visual-factory-impl.cpp
dali-toolkit/internal/visuals/visual-url.cpp
dali-toolkit/internal/visuals/visual-url.h

index aef362b7e935bfca34ac143572b406ce1c9017d0..01d4d37928ac6cf3e152b7f2690d0fc8710db728 100644 (file)
@@ -510,32 +510,11 @@ int UtcTextureManagerEncodedImageBufferWithImageType(void)
 int UtcTextureManagerExternalTexture(void)
 {
   ToolkitTestApplication application;
-  tet_infoline("UtcTextureManagerExternalTexture check TextureManager using external texture works well");
+  tet_infoline("UtcTextureManagerExternalTexture check TextureManager using external texture as image, or masking, or both works well");
 
   auto  visualFactory  = Toolkit::VisualFactory::Get();
   auto& textureManager = GetImplementation(visualFactory).GetTextureManager(); // Use VisualFactory's texture manager
 
-  TestObserver observer1;
-  TestObserver observer2;
-
-  auto                               textureId1(TextureManager::INVALID_TEXTURE_ID);
-  auto                               textureId2(TextureManager::INVALID_TEXTURE_ID);
-  std::string                        maskname(TEST_MASK_FILE_NAME);
-  TextureManager::MaskingDataPointer maskInfo = nullptr;
-  maskInfo.reset(new TextureManager::MaskingData());
-  maskInfo->mAlphaMaskUrl       = maskname;
-  maskInfo->mAlphaMaskId        = TextureManager::INVALID_TEXTURE_ID;
-  maskInfo->mCropToMask         = true;
-  maskInfo->mContentScaleFactor = 1.0f;
-  Vector4                       atlasRect(0.f, 0.f, 1.f, 1.f);
-  Dali::ImageDimensions         atlasRectSize(0, 0);
-  bool                          synchronousLoading(false);
-  bool                          atlasingStatus(false);
-  bool                          loadingStatus(false);
-  auto                          preMultiply         = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
-  ImageAtlasManagerPtr          atlasManager        = nullptr;
-  Toolkit::AtlasUploadObserver* atlasUploadObserver = nullptr;
-
   uint32_t width(64);
   uint32_t height(64);
   uint32_t bufferSize = width * height * Pixel::GetBytesPerPixel(Pixel::RGBA8888);
@@ -545,110 +524,181 @@ int UtcTextureManagerExternalTexture(void)
 
   DALI_TEST_CHECK(pixelData);
 
-  Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(pixelData, true);
-  std::string             url      = imageUrl.GetUrl();
+  Dali::Toolkit::ImageUrl imageUrl          = Dali::Toolkit::Image::GenerateUrl(pixelData, true);
+  std::string             externalImageUrl  = imageUrl.GetUrl();
+  Dali::Toolkit::ImageUrl imageUrl2         = Dali::Toolkit::Image::GenerateUrl(pixelData, false);
+  std::string             externalImageUrl2 = imageUrl2.GetUrl();
 
-  TextureSet texture1 = textureManager.LoadTexture(
-    url,
-    ImageDimensions(),
-    FittingMode::SCALE_TO_FILL,
-    SamplingMode::BOX_THEN_LINEAR,
-    maskInfo,
-    synchronousLoading,
-    textureId1,
-    atlasRect,
-    atlasRectSize,
-    atlasingStatus,
-    loadingStatus,
-    &observer1,
-    atlasUploadObserver,
-    atlasManager,
-    true,
-    TextureManager::ReloadPolicy::CACHED,
-    preMultiply);
+  for(int testCase = 0; testCase < 6; testCase++)
+  {
+    // Test case config
+    // Note tat we don't need to test (!testExternalTexture && !testExternalMask) case.
+    const bool testSyncLoad        = ((testCase & 0x01) == 0);
+    const bool testExternalTexture = ((testCase & 0x02) == 0);
+    const bool testExternalMask    = ((testCase & 0x04) == 0);
 
-  TextureSet texture2 = textureManager.LoadTexture(
-    url,
-    ImageDimensions(),
-    FittingMode::SCALE_TO_FILL,
-    SamplingMode::BOX_THEN_LINEAR,
-    maskInfo,
-    synchronousLoading,
-    textureId2,
-    atlasRect,
-    atlasRectSize,
-    atlasingStatus,
-    loadingStatus,
-    &observer2,
-    atlasUploadObserver,
-    atlasManager,
-    true,
-    TextureManager::ReloadPolicy::CACHED,
-    preMultiply);
+    tet_printf("Testcase, syncload : %d, externalTexture : %d, externalMask : %d\n", testSyncLoad, testExternalTexture, testExternalMask);
 
-  DALI_TEST_EQUALS(observer1.mLoaded, false, TEST_LOCATION);
-  DALI_TEST_EQUALS(observer1.mObserverCalled, false, TEST_LOCATION);
-  DALI_TEST_EQUALS(observer2.mLoaded, false, TEST_LOCATION);
-  DALI_TEST_EQUALS(observer2.mObserverCalled, false, TEST_LOCATION);
+    // texture loaded only if it is syncload, or both of textures are external.
+    const bool expectTextureLoadedResult = testSyncLoad || (testExternalTexture && testExternalMask);
+    const bool expectObserverNotified    = !testSyncLoad && (testExternalTexture && testExternalMask);
 
-  application.SendNotification();
-  application.Render();
+    auto textureId1(TextureManager::INVALID_TEXTURE_ID);
+    auto textureId2(TextureManager::INVALID_TEXTURE_ID);
 
-  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+    TestObserver observer1;
+    TestObserver observer2;
 
-  DALI_TEST_EQUALS(observer1.mLoaded, true, TEST_LOCATION);
-  DALI_TEST_EQUALS(observer1.mObserverCalled, true, TEST_LOCATION);
-  DALI_TEST_EQUALS(observer1.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION);
+    std::string                        maskname(testExternalMask ? externalImageUrl2 : TEST_MASK_FILE_NAME);
+    TextureManager::MaskingDataPointer maskInfo = nullptr;
+    maskInfo.reset(new TextureManager::MaskingData());
+    maskInfo->mAlphaMaskUrl       = maskname;
+    maskInfo->mAlphaMaskId        = TextureManager::INVALID_TEXTURE_ID;
+    maskInfo->mCropToMask         = true;
+    maskInfo->mContentScaleFactor = 1.0f;
+    maskInfo->mPreappliedMasking  = false;
 
-  DALI_TEST_EQUALS(observer2.mLoaded, true, TEST_LOCATION);
-  DALI_TEST_EQUALS(observer2.mObserverCalled, true, TEST_LOCATION);
-  DALI_TEST_EQUALS(observer2.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION);
+    Vector4                       atlasRect(0.f, 0.f, 1.f, 1.f);
+    Dali::ImageDimensions         atlasRectSize(0, 0);
+    bool                          synchronousLoading(testSyncLoad);
+    bool                          atlasingStatus(false);
+    bool                          loadingStatus(false);
+    auto                          preMultiply         = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+    ImageAtlasManagerPtr          atlasManager        = nullptr;
+    Toolkit::AtlasUploadObserver* atlasUploadObserver = nullptr;
 
-  DALI_TEST_EQUALS(textureId1 == textureId2, true, TEST_LOCATION);
+    std::string url(testExternalTexture ? externalImageUrl : TEST_IMAGE_FILE_NAME);
 
-  texture1 = textureManager.LoadTexture(
-    url,
-    ImageDimensions(),
-    FittingMode::SCALE_TO_FILL,
-    SamplingMode::BOX_THEN_LINEAR,
-    maskInfo,
-    synchronousLoading,
-    textureId1,
-    atlasRect,
-    atlasRectSize,
-    atlasingStatus,
-    loadingStatus,
-    &observer1,
-    atlasUploadObserver,
-    atlasManager,
-    true,
-    TextureManager::ReloadPolicy::CACHED,
-    preMultiply);
+    TextureSet texture1 = textureManager.LoadTexture(
+      url,
+      ImageDimensions(),
+      FittingMode::SCALE_TO_FILL,
+      SamplingMode::BOX_THEN_LINEAR,
+      maskInfo,
+      synchronousLoading,
+      textureId1,
+      atlasRect,
+      atlasRectSize,
+      atlasingStatus,
+      loadingStatus,
+      &observer1,
+      atlasUploadObserver,
+      atlasManager,
+      true,
+      TextureManager::ReloadPolicy::CACHED,
+      preMultiply);
 
-  texture2 = textureManager.LoadTexture(
-    url,
-    ImageDimensions(),
-    FittingMode::SCALE_TO_FILL,
-    SamplingMode::BOX_THEN_LINEAR,
-    maskInfo,
-    synchronousLoading,
-    textureId2,
-    atlasRect,
-    atlasRectSize,
-    atlasingStatus,
-    loadingStatus,
-    &observer2,
-    atlasUploadObserver,
-    atlasManager,
-    true,
-    TextureManager::ReloadPolicy::CACHED,
-    preMultiply);
+    DALI_TEST_EQUALS(!!texture1, expectTextureLoadedResult, TEST_LOCATION);
 
-  application.SendNotification();
-  application.Render();
+    TextureSet texture2 = textureManager.LoadTexture(
+      url,
+      ImageDimensions(),
+      FittingMode::SCALE_TO_FILL,
+      SamplingMode::BOX_THEN_LINEAR,
+      maskInfo,
+      synchronousLoading,
+      textureId2,
+      atlasRect,
+      atlasRectSize,
+      atlasingStatus,
+      loadingStatus,
+      &observer2,
+      atlasUploadObserver,
+      atlasManager,
+      true,
+      TextureManager::ReloadPolicy::CACHED,
+      preMultiply);
 
-  DALI_TEST_EQUALS(textureId1 == textureId2, true, TEST_LOCATION);
-  DALI_TEST_EQUALS(texture1 != texture2, true, TEST_LOCATION);
+    DALI_TEST_EQUALS(!!texture2, expectTextureLoadedResult, TEST_LOCATION);
+
+    DALI_TEST_EQUALS(observer1.mLoaded, expectObserverNotified, TEST_LOCATION);
+    DALI_TEST_EQUALS(observer1.mObserverCalled, expectObserverNotified, TEST_LOCATION);
+    DALI_TEST_EQUALS(observer2.mLoaded, expectObserverNotified, TEST_LOCATION);
+    DALI_TEST_EQUALS(observer2.mObserverCalled, expectObserverNotified, TEST_LOCATION);
+
+    DALI_TEST_EQUALS(textureId1 == textureId2, true, TEST_LOCATION);
+
+    application.SendNotification();
+    application.Render();
+
+    if(!expectTextureLoadedResult)
+    {
+      DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+    }
+
+    if(!testSyncLoad)
+    {
+      DALI_TEST_EQUALS(observer1.mLoaded, true, TEST_LOCATION);
+      DALI_TEST_EQUALS(observer1.mObserverCalled, true, TEST_LOCATION);
+      DALI_TEST_EQUALS(observer1.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION);
+
+      DALI_TEST_EQUALS(observer2.mLoaded, true, TEST_LOCATION);
+      DALI_TEST_EQUALS(observer2.mObserverCalled, true, TEST_LOCATION);
+      DALI_TEST_EQUALS(observer2.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION);
+    }
+
+    application.SendNotification();
+    application.Render();
+
+    texture1 = textureManager.LoadTexture(
+      url,
+      ImageDimensions(),
+      FittingMode::SCALE_TO_FILL,
+      SamplingMode::BOX_THEN_LINEAR,
+      maskInfo,
+      synchronousLoading,
+      textureId1,
+      atlasRect,
+      atlasRectSize,
+      atlasingStatus,
+      loadingStatus,
+      &observer1,
+      atlasUploadObserver,
+      atlasManager,
+      true,
+      TextureManager::ReloadPolicy::CACHED,
+      preMultiply);
+
+    DALI_TEST_CHECK(texture1); // texture is loaded.
+
+    texture2 = textureManager.LoadTexture(
+      url,
+      ImageDimensions(),
+      FittingMode::SCALE_TO_FILL,
+      SamplingMode::BOX_THEN_LINEAR,
+      maskInfo,
+      synchronousLoading,
+      textureId2,
+      atlasRect,
+      atlasRectSize,
+      atlasingStatus,
+      loadingStatus,
+      &observer2,
+      atlasUploadObserver,
+      atlasManager,
+      true,
+      TextureManager::ReloadPolicy::CACHED,
+      preMultiply);
+
+    DALI_TEST_CHECK(texture2); // texture is loaded.
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS(textureId1 == textureId2, true, TEST_LOCATION);
+    DALI_TEST_EQUALS(texture1 != texture2, true, TEST_LOCATION);
+
+    // Ensure to remove cache.
+    textureManager.RequestRemove(textureId1, nullptr);
+    textureManager.RequestRemove(textureId1, nullptr);
+    textureManager.RequestRemove(textureId1, nullptr);
+    textureManager.RequestRemove(textureId1, nullptr);
+
+    application.SendNotification();
+    application.Render();
+    application.SendNotification();
+    application.Render();
+  }
 
   END_TEST;
 }
@@ -712,6 +762,14 @@ int UtcTextureManagerRemoveExternalTextureAndLoadAgain(void)
 
   DALI_TEST_CHECK(textureId1 != TextureManager::INVALID_TEXTURE_ID);
 
+  // Note that ExernalTexture will notify observer.
+  DALI_TEST_EQUALS(observer1.mLoaded, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer1.mObserverCalled, true, TEST_LOCATION);
+
+  // Reset flags for observer1.
+  observer1.mLoaded         = false;
+  observer1.mObserverCalled = false;
+
   // Step 2 : Request remove for external url
   textureManager.RequestRemove(textureId1, &observer1);
 
@@ -2418,3 +2476,296 @@ int UtcTextureManagerCachingForDifferentMultiplyOnLoad(void)
 
   END_TEST;
 }
+
+int UtcTextureManagerMaskByExternalTexture01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcTextureManagerMaskByExternalTexture01 check TextureManager masking by external texture works well");
+
+  auto  visualFactory  = Toolkit::VisualFactory::Get();
+  auto& textureManager = GetImplementation(visualFactory).GetTextureManager(); // Use VisualFactory's texture manager
+
+  uint32_t width(64);
+  uint32_t height(64);
+  uint32_t bufferSize = width * height * Pixel::GetBytesPerPixel(Pixel::RGBA8888);
+
+  uint8_t*                buffer    = reinterpret_cast<uint8_t*>(malloc(bufferSize));
+  PixelData               pixelData = PixelData::New(buffer, bufferSize, width, height, Pixel::RGBA8888, PixelData::FREE);
+  Dali::Toolkit::ImageUrl imageUrl  = Dali::Toolkit::Image::GenerateUrl(pixelData, true);
+
+  TestObserver observer1;
+  TestObserver observer2;
+
+  auto                               textureId1(TextureManager::INVALID_TEXTURE_ID);
+  auto                               textureId2(TextureManager::INVALID_TEXTURE_ID);
+  TextureManager::MaskingDataPointer maskInfo = nullptr;
+
+  maskInfo.reset(new TextureManager::MaskingData());
+  maskInfo->mAlphaMaskUrl       = imageUrl.GetUrl();
+  maskInfo->mAlphaMaskId        = TextureManager::INVALID_TEXTURE_ID;
+  maskInfo->mCropToMask         = true;
+  maskInfo->mContentScaleFactor = 1.0f;
+  maskInfo->mPreappliedMasking  = false;
+
+  Vector4                       atlasRect(0.f, 0.f, 1.f, 1.f);
+  Dali::ImageDimensions         atlasRectSize(0, 0);
+  bool                          synchronousLoading(false);
+  bool                          atlasingStatus(false);
+  bool                          loadingStatus(false);
+  auto                          preMultiply         = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+  ImageAtlasManagerPtr          atlasManager        = nullptr;
+  Toolkit::AtlasUploadObserver* atlasUploadObserver = nullptr;
+
+  DALI_TEST_CHECK(pixelData);
+
+  std::string url = TEST_IMAGE_FILE_NAME;
+
+  TextureSet texture1 = textureManager.LoadTexture(
+    url,
+    ImageDimensions(),
+    FittingMode::SCALE_TO_FILL,
+    SamplingMode::BOX_THEN_LINEAR,
+    maskInfo,
+    synchronousLoading,
+    textureId1,
+    atlasRect,
+    atlasRectSize,
+    atlasingStatus,
+    loadingStatus,
+    &observer1,
+    atlasUploadObserver,
+    atlasManager,
+    true,
+    TextureManager::ReloadPolicy::CACHED,
+    preMultiply);
+
+  TextureSet texture2 = textureManager.LoadTexture(
+    url,
+    ImageDimensions(),
+    FittingMode::SCALE_TO_FILL,
+    SamplingMode::BOX_THEN_LINEAR,
+    maskInfo,
+    synchronousLoading,
+    textureId2,
+    atlasRect,
+    atlasRectSize,
+    atlasingStatus,
+    loadingStatus,
+    &observer2,
+    atlasUploadObserver,
+    atlasManager,
+    true,
+    TextureManager::ReloadPolicy::CACHED,
+    preMultiply);
+
+  DALI_TEST_EQUALS(observer1.mLoaded, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer1.mObserverCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer2.mLoaded, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer2.mObserverCalled, false, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(observer1.mLoaded, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer1.mObserverCalled, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer1.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(observer2.mLoaded, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer2.mObserverCalled, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer2.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(textureId1 == textureId2, true, TEST_LOCATION);
+
+  texture1 = textureManager.LoadTexture(
+    url,
+    ImageDimensions(),
+    FittingMode::SCALE_TO_FILL,
+    SamplingMode::BOX_THEN_LINEAR,
+    maskInfo,
+    synchronousLoading,
+    textureId1,
+    atlasRect,
+    atlasRectSize,
+    atlasingStatus,
+    loadingStatus,
+    &observer1,
+    atlasUploadObserver,
+    atlasManager,
+    true,
+    TextureManager::ReloadPolicy::CACHED,
+    preMultiply);
+
+  texture2 = textureManager.LoadTexture(
+    url,
+    ImageDimensions(),
+    FittingMode::SCALE_TO_FILL,
+    SamplingMode::BOX_THEN_LINEAR,
+    maskInfo,
+    synchronousLoading,
+    textureId2,
+    atlasRect,
+    atlasRectSize,
+    atlasingStatus,
+    loadingStatus,
+    &observer2,
+    atlasUploadObserver,
+    atlasManager,
+    true,
+    TextureManager::ReloadPolicy::CACHED,
+    preMultiply);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(textureId1 == textureId2, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(texture1 != texture2, true, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcTextureManagerMaskByExternalTexture02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcTextureManagerMaskByExternalTexture02 check TextureManager masking external texture by external texture works well");
+
+  auto  visualFactory  = Toolkit::VisualFactory::Get();
+  auto& textureManager = GetImplementation(visualFactory).GetTextureManager(); // Use VisualFactory's texture manager
+
+  uint32_t width(64);
+  uint32_t height(64);
+  uint32_t bufferSize = width * height * Pixel::GetBytesPerPixel(Pixel::RGBA8888);
+
+  uint8_t*                buffer    = reinterpret_cast<uint8_t*>(malloc(bufferSize));
+  PixelData               pixelData = PixelData::New(buffer, bufferSize, width, height, Pixel::RGBA8888, PixelData::FREE);
+  Dali::Toolkit::ImageUrl imageUrl  = Dali::Toolkit::Image::GenerateUrl(pixelData, true);
+  Dali::Toolkit::ImageUrl imageUrl2 = Dali::Toolkit::Image::GenerateUrl(pixelData, true);
+
+  TestObserver observer1;
+  TestObserver observer2;
+
+  auto                               textureId1(TextureManager::INVALID_TEXTURE_ID);
+  auto                               textureId2(TextureManager::INVALID_TEXTURE_ID);
+  TextureManager::MaskingDataPointer maskInfo = nullptr;
+
+  maskInfo.reset(new TextureManager::MaskingData());
+  maskInfo->mAlphaMaskUrl       = imageUrl.GetUrl();
+  maskInfo->mAlphaMaskId        = TextureManager::INVALID_TEXTURE_ID;
+  maskInfo->mCropToMask         = true;
+  maskInfo->mContentScaleFactor = 1.0f;
+  maskInfo->mPreappliedMasking  = false;
+
+  Vector4                       atlasRect(0.f, 0.f, 1.f, 1.f);
+  Dali::ImageDimensions         atlasRectSize(0, 0);
+  bool                          synchronousLoading(false);
+  bool                          atlasingStatus(false);
+  bool                          loadingStatus(false);
+  auto                          preMultiply         = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+  ImageAtlasManagerPtr          atlasManager        = nullptr;
+  Toolkit::AtlasUploadObserver* atlasUploadObserver = nullptr;
+
+  DALI_TEST_CHECK(pixelData);
+
+  std::string url = imageUrl2.GetUrl();
+
+  TextureSet texture1 = textureManager.LoadTexture(
+    url,
+    ImageDimensions(),
+    FittingMode::SCALE_TO_FILL,
+    SamplingMode::BOX_THEN_LINEAR,
+    maskInfo,
+    synchronousLoading,
+    textureId1,
+    atlasRect,
+    atlasRectSize,
+    atlasingStatus,
+    loadingStatus,
+    &observer1,
+    atlasUploadObserver,
+    atlasManager,
+    true,
+    TextureManager::ReloadPolicy::CACHED,
+    preMultiply);
+
+  TextureSet texture2 = textureManager.LoadTexture(
+    url,
+    ImageDimensions(),
+    FittingMode::SCALE_TO_FILL,
+    SamplingMode::BOX_THEN_LINEAR,
+    maskInfo,
+    synchronousLoading,
+    textureId2,
+    atlasRect,
+    atlasRectSize,
+    atlasingStatus,
+    loadingStatus,
+    &observer2,
+    atlasUploadObserver,
+    atlasManager,
+    true,
+    TextureManager::ReloadPolicy::CACHED,
+    preMultiply);
+
+  tet_printf("url : %s, mask url : %s, textureid : %d %d\n", url.c_str(), maskInfo->mAlphaMaskUrl.GetUrl().c_str(), textureId1, textureId2);
+
+  // observer called synchronously. (Since external textures are already uploaded)
+  DALI_TEST_EQUALS(observer1.mLoaded, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer1.mObserverCalled, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer1.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(observer2.mLoaded, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer2.mObserverCalled, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer2.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(textureId1 == textureId2, true, TEST_LOCATION);
+
+  texture1 = textureManager.LoadTexture(
+    url,
+    ImageDimensions(),
+    FittingMode::SCALE_TO_FILL,
+    SamplingMode::BOX_THEN_LINEAR,
+    maskInfo,
+    synchronousLoading,
+    textureId1,
+    atlasRect,
+    atlasRectSize,
+    atlasingStatus,
+    loadingStatus,
+    &observer1,
+    atlasUploadObserver,
+    atlasManager,
+    true,
+    TextureManager::ReloadPolicy::CACHED,
+    preMultiply);
+
+  texture2 = textureManager.LoadTexture(
+    url,
+    ImageDimensions(),
+    FittingMode::SCALE_TO_FILL,
+    SamplingMode::BOX_THEN_LINEAR,
+    maskInfo,
+    synchronousLoading,
+    textureId2,
+    atlasRect,
+    atlasRectSize,
+    atlasingStatus,
+    loadingStatus,
+    &observer2,
+    atlasUploadObserver,
+    atlasManager,
+    true,
+    TextureManager::ReloadPolicy::CACHED,
+    preMultiply);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(textureId1 == textureId2, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(texture1 != texture2, true, TEST_LOCATION);
+
+  END_TEST;
+}
index f94764db1310983786bed215e2bcde973d456ef0..1ab8c5ff5edec067ec63043578c20f81368b041e 100644 (file)
@@ -29,7 +29,18 @@ using namespace Dali::Toolkit::Internal;
 namespace
 {
 constexpr uint32_t URL_ELLIPSED_LENGTH = 20u;
+
+void TestLocationAsInteger(const char* url, int32_t expectValue, bool expectResult, const char* testLocation)
+{
+  int32_t result    = 0;
+  bool    successed = VisualUrl(url).GetLocationAsInteger(result);
+  DALI_TEST_EQUALS(successed, expectResult, testLocation);
+  if(successed)
+  {
+    DALI_TEST_EQUALS(result, expectValue, testLocation);
+  }
 }
+} // namespace
 
 int UtcDaliVisualUrlConstructor(void)
 {
@@ -433,6 +444,25 @@ int UtcDaliVisualUrlGetLocationWithoutExtensionP(void)
   DALI_TEST_EQUAL("", VisualUrl("ftp://.png").GetLocationWithoutExtension());
   DALI_TEST_EQUAL("http://a.jpg", VisualUrl("http://http://a.jpg.jpg").GetLocationWithoutExtension());
 
+  DALI_TEST_EQUAL("a", VisualUrl("a.jpg").GetLocationWithoutExtension());
+  DALI_TEST_EQUAL("12", VisualUrl("12.png").GetLocationWithoutExtension());
+  DALI_TEST_EQUAL("/usr/bin/hello", VisualUrl("/usr/bin/hello.txt").GetLocationWithoutExtension());
+
+  END_TEST;
+}
+
+int UtcDaliVisualUrlGetLocationAsIntegerP(void)
+{
+  tet_infoline("UtcDaliVisualUrl GetLocationAsInteger Positive");
+
+  TestLocationAsInteger("http://1.png", 1, true, TEST_LOCATION);
+  TestLocationAsInteger("dali://2", 2, true, TEST_LOCATION);
+  TestLocationAsInteger("enbuf://4.svg", 4, true, TEST_LOCATION);
+  TestLocationAsInteger("ftp://-2", -2, true, TEST_LOCATION);
+  TestLocationAsInteger("9.png", 9, true, TEST_LOCATION);
+  TestLocationAsInteger("2147483647", 2147483647, true, TEST_LOCATION);
+  TestLocationAsInteger("-2147483648.jpg", -2147483648, true, TEST_LOCATION);
+
   END_TEST;
 }
 
@@ -456,14 +486,29 @@ int UtcDaliVisualUrlGetLocationWithoutExtensionN(void)
 
   DALI_TEST_EQUAL("", VisualUrl("").GetLocationWithoutExtension());
   DALI_TEST_EQUAL("a", VisualUrl("a").GetLocationWithoutExtension());
-  DALI_TEST_EQUAL("dali:/1.jpg", VisualUrl("dali:/1.jpg").GetLocationWithoutExtension());
-  DALI_TEST_EQUAL("dali//1.jpg", VisualUrl("dali//1.jpg").GetLocationWithoutExtension());
-  DALI_TEST_EQUAL("enbuf:/2.png", VisualUrl("enbuf:/2.png").GetLocationWithoutExtension());
+  DALI_TEST_EQUAL("dali:/1", VisualUrl("dali:/1").GetLocationWithoutExtension());
+  DALI_TEST_EQUAL("dali//1", VisualUrl("dali//1").GetLocationWithoutExtension());
+  DALI_TEST_EQUAL("enbuf:/2", VisualUrl("enbuf:/2.png").GetLocationWithoutExtension());
   DALI_TEST_EQUAL("a.jpg", VisualUrl("http:/http://a.jpg.jpngif").GetLocationWithoutExtension());
 
   END_TEST;
 }
 
+int UtcDaliVisualUrlGetLocationAsIntegerN(void)
+{
+  tet_infoline("UtcDaliVisualUrl GetLocationAsInteger Positive");
+
+  TestLocationAsInteger("http://abc.png", 0, false, TEST_LOCATION);
+  TestLocationAsInteger("dali://.png.png", 0, false, TEST_LOCATION);
+  TestLocationAsInteger("enbuf://.svg", 0, false, TEST_LOCATION);
+  TestLocationAsInteger("ftp://", 0, false, TEST_LOCATION);
+
+  TestLocationAsInteger("2147483648", 0, false, TEST_LOCATION);
+  TestLocationAsInteger("-2147483649", 0, false, TEST_LOCATION);
+
+  END_TEST;
+}
+
 int UtcDaliVisualUrlCreateTextureUrl(void)
 {
   tet_infoline("UtcDaliVisualUrl CreateTextureUrl");
index bdb68dc53d2b4d7148198f80e0b4d959eec48f20..458b5cd9fb9e4888f4117b1ac2876702fb1636cf 100644 (file)
 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
 #include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
 #include <dali/devel-api/adaptor-framework/window-devel.h>
 
 #include "dummy-control.h"
+#include "test-encoded-image-buffer.h"
 
 using namespace Dali;
 using namespace Dali::Toolkit;
@@ -57,8 +60,6 @@ const char* TEST_N_PATCH_IMAGE_FILE_NAME         = TEST_RESOURCE_DIR "/heartsfra
 const char* TEST_SVG_FILE_NAME                   = TEST_RESOURCE_DIR "/svg1.svg";
 const char* TEST_ANIMATED_VECTOR_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/insta_camera.json";
 
-} // namespace
-
 void CopyUrlsIntoArray(Property::Array& urls, int startIndex = 0)
 {
   for(int i = 20 + startIndex; i <= 30; ++i)
@@ -73,6 +74,67 @@ void CopyUrlsIntoArray(Property::Array& urls, int startIndex = 0)
   }
 }
 
+enum ExternalUrlType
+{
+  EXTERNAL_TEXTURE,
+  ENCODED_IMAGE_BUFFER,
+  MIXED,
+};
+
+ImageUrl ConvertFileToImageUrl(const char* url, ExternalUrlType type)
+{
+  DALI_ASSERT_ALWAYS(type == ExternalUrlType::EXTERNAL_TEXTURE || type == ExternalUrlType::ENCODED_IMAGE_BUFFER);
+
+  ImageUrl imageUrl;
+
+  if(type == ExternalUrlType::EXTERNAL_TEXTURE)
+  {
+    Devel::PixelBuffer pixelBuffer = LoadImageFromFile(url);
+    PixelData          pixelData   = Devel::PixelBuffer::Convert(pixelBuffer);
+
+    imageUrl = Dali::Toolkit::Image::GenerateUrl(pixelData);
+  }
+  else // ENCODED_IMAGE_BUFFER
+  {
+    EncodedImageBuffer rawBuffer = ConvertFileToEncodedImageBuffer(url);
+
+    imageUrl = Dali::Toolkit::Image::GenerateUrl(rawBuffer);
+  }
+
+  return imageUrl;
+}
+
+void CopyExternalUrlsIntoArray(Property::Array& urls, std::vector<ImageUrl>& imageUrlContainer, int startIndex, ExternalUrlType generationType)
+{
+  for(int i = 20 + startIndex; i <= 30; ++i)
+  {
+    char* url;
+    if(asprintf(&url, TEST_IMAGE_FILE_NAME, i) > 0)
+    {
+      ImageUrl imageUrl;
+      if(generationType == ExternalUrlType::EXTERNAL_TEXTURE ||
+         (generationType == ExternalUrlType::MIXED && (i % 2 == 0)))
+      {
+        imageUrl = ConvertFileToImageUrl(url, ExternalUrlType::EXTERNAL_TEXTURE);
+      }
+      else // ENCODED_IMAGE_BUFFER
+      {
+        imageUrl = ConvertFileToImageUrl(url, ExternalUrlType::ENCODED_IMAGE_BUFFER);
+      }
+
+      DALI_TEST_CHECK(imageUrl);
+
+      imageUrlContainer.push_back(imageUrl); ///< To keep reference count of external textures.
+
+      Property::Value value(imageUrl.GetUrl());
+      urls.Add(value);
+      free(url);
+    }
+  }
+}
+
+} // namespace
+
 int UtcDaliAnimatedImageVisualGetPropertyMap01(void)
 {
   ToolkitTestApplication application;
@@ -741,6 +803,10 @@ int UtcDaliAnimatedImageVisualSynchronousLoading(void)
     dummyControl.Unparent();
   }
   tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(16);
+  application.RunIdles();
   application.SendNotification();
   application.Render(16);
   DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
@@ -786,8 +852,8 @@ int UtcDaliAnimatedImageVisualSynchronousLoadingWithAlphaMask01(void)
     application.SendNotification();
     application.Render(20);
 
-    // The first frame is loaded synchronously and load next batch with masking
-    DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(3), true, TEST_LOCATION);
+    // The first frame is loaded synchronously and load next batch with masking (1 for load, 1 for apply masking)
+    DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
 
     application.SendNotification();
     application.Render();
@@ -798,6 +864,10 @@ int UtcDaliAnimatedImageVisualSynchronousLoadingWithAlphaMask01(void)
     dummyControl.Unparent();
   }
   tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(16);
+  application.RunIdles();
   application.SendNotification();
   application.Render(16);
   DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
@@ -844,21 +914,27 @@ int UtcDaliAnimatedImageVisualSynchronousLoadingWithAlphaMask02(void)
     application.SendNotification();
     application.Render(20);
 
-    // The first frame is loaded synchronously and load next batch with masking
-    DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+    // The first frame is loaded synchronously and load next batch
+    DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
 
     application.SendNotification();
     application.Render();
 
     DALI_TEST_EQUALS(Test::GetTimerCount(), 1, TEST_LOCATION);
-    DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 4, TEST_LOCATION);
+    DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 3, TEST_LOCATION);
 
     dummyControl.Unparent();
   }
   tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.RunIdles();
   application.SendNotification();
   application.Render(16);
-  DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(16);
+
+  // TODO : It will be failed due to we don't cache SyncLoading case. fix it soon
+  //DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
 
   END_TEST;
 }
@@ -921,6 +997,10 @@ int UtcDaliAnimatedImageVisualJumpToAction(void)
     dummyControl.Unparent();
   }
   tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(16);
+  application.RunIdles();
   application.SendNotification();
   application.Render(16);
   DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
@@ -988,6 +1068,10 @@ int UtcDaliAnimatedImageVisualStopBehavior(void)
     dummyControl.Unparent();
   }
   tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(16);
+  application.RunIdles();
   application.SendNotification();
   application.Render(16);
   DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
@@ -1058,6 +1142,10 @@ int UtcDaliAnimatedImageVisualStopBehavior02(void)
     dummyControl.Unparent();
   }
   tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(16);
+  application.RunIdles();
   application.SendNotification();
   application.Render(16);
   DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
@@ -1166,6 +1254,10 @@ int UtcDaliAnimatedImageVisualAnimatedImage01(void)
     dummyControl2.Unparent();
   }
   tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(20);
+  application.RunIdles();
   application.SendNotification();
   application.Render(20);
   DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
@@ -1212,6 +1304,10 @@ int UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask01(void)
     dummyControl.Unparent();
   }
   tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(20);
+  application.RunIdles();
   application.SendNotification();
   application.Render(20);
   DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
@@ -1251,7 +1347,7 @@ int UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask02(void)
     application.SendNotification();
     application.Render();
 
-    // load two frame(batch size), load mask image, and request two masking
+    // load two frame(batch size), load mask image, and do not request two masking
     DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(3), true, TEST_LOCATION);
 
     application.SendNotification();
@@ -1262,6 +1358,10 @@ int UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask02(void)
     dummyControl.Unparent();
   }
   tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(20);
+  application.RunIdles();
   application.SendNotification();
   application.Render(20);
   DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
@@ -1272,7 +1372,57 @@ int UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask02(void)
 int UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask03(void)
 {
   ToolkitTestApplication application;
-  tet_infoline("UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask03 for GPU Alpha Masking with broken mask texture");
+  tet_infoline("UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask03 for CPU Alpha Masking with broken mask texture");
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  {
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE, Visual::ANIMATED_IMAGE);
+    propertyMap.Insert(ImageVisual::Property::URL, TEST_GIF_FILE_NAME);
+    propertyMap.Insert(ImageVisual::Property::BATCH_SIZE, 2);
+    propertyMap.Insert(ImageVisual::Property::CACHE_SIZE, 4);
+    propertyMap.Insert(ImageVisual::Property::FRAME_DELAY, 20);
+    propertyMap.Insert(ImageVisual::Property::ALPHA_MASK_URL, "invalid.jpg");
+
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base  visual  = factory.CreateVisual(propertyMap);
+
+    DummyControl        dummyControl = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl    = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+    dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual);
+
+    dummyControl.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+    application.GetScene().Add(dummyControl);
+
+    application.SendNotification();
+    application.Render();
+
+    // load two frame(batch size), load mask image, and do not request two masking
+    DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(3), true, TEST_LOCATION);
+
+    application.SendNotification();
+    application.Render(20);
+
+    DALI_TEST_EQUALS(gl.GetLastGenTextureId(), 2, TEST_LOCATION);
+
+    dummyControl.Unparent();
+  }
+  tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(20);
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(20);
+  DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask04(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask04 for GPU Alpha Masking with broken mask texture");
   TestGlAbstraction& gl = application.GetGlAbstraction();
 
   {
@@ -1282,7 +1432,7 @@ int UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask03(void)
     propertyMap.Insert(ImageVisual::Property::BATCH_SIZE, 2);
     propertyMap.Insert(ImageVisual::Property::CACHE_SIZE, 4);
     propertyMap.Insert(ImageVisual::Property::FRAME_DELAY, 20);
-    propertyMap.Insert(ImageVisual::Property::ALPHA_MASK_URL, "");
+    propertyMap.Insert(ImageVisual::Property::ALPHA_MASK_URL, "invalid.jpg");
     propertyMap.Insert(DevelImageVisual::Property::MASKING_TYPE, DevelImageVisual::MaskingType::MASKING_ON_RENDERING);
 
     VisualFactory factory = VisualFactory::Get();
@@ -1298,7 +1448,116 @@ int UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask03(void)
     application.SendNotification();
     application.Render();
 
+    // load two frame(batch size), load mask image, and do not request two masking
+    DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(3), true, TEST_LOCATION);
+
+    application.SendNotification();
+    application.Render(20);
+
+    DALI_TEST_EQUALS(gl.GetLastGenTextureId(), 2, TEST_LOCATION);
+
+    dummyControl.Unparent();
+  }
+  tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(20);
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(20);
+  DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask05(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask05 for CPU Alpha Masking with encoded image buffer");
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  {
+    EncodedImageBuffer rawBuffer = ConvertFileToEncodedImageBuffer(TEST_MASK_IMAGE_FILE_NAME);
+    ImageUrl           imageUrl  = Dali::Toolkit::Image::GenerateUrl(rawBuffer);
+    std::string        url       = imageUrl.GetUrl();
+
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE, Visual::ANIMATED_IMAGE);
+    propertyMap.Insert(ImageVisual::Property::URL, TEST_GIF_FILE_NAME);
+    propertyMap.Insert(ImageVisual::Property::BATCH_SIZE, 2);
+    propertyMap.Insert(ImageVisual::Property::CACHE_SIZE, 4);
+    propertyMap.Insert(ImageVisual::Property::FRAME_DELAY, 20);
+    propertyMap.Insert(ImageVisual::Property::ALPHA_MASK_URL, url);
+
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base  visual  = factory.CreateVisual(propertyMap);
+
+    DummyControl        dummyControl = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl    = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+    dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual);
+
+    dummyControl.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+    application.GetScene().Add(dummyControl);
+
+    application.SendNotification();
+    application.Render();
+
     // load two frame(batch size), load mask image, and request two masking
+    DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(5), true, TEST_LOCATION);
+
+    application.SendNotification();
+    application.Render(20);
+
+    DALI_TEST_EQUALS(gl.GetLastGenTextureId(), 2, TEST_LOCATION);
+
+    dummyControl.Unparent();
+  }
+  tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(20);
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(20);
+  DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask06(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask06 for GPU Alpha Masking with encoded image buffer");
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  {
+    EncodedImageBuffer rawBuffer = ConvertFileToEncodedImageBuffer(TEST_MASK_IMAGE_FILE_NAME);
+    ImageUrl           imageUrl  = Dali::Toolkit::Image::GenerateUrl(rawBuffer);
+    std::string        url       = imageUrl.GetUrl();
+
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE, Visual::ANIMATED_IMAGE);
+    propertyMap.Insert(ImageVisual::Property::URL, TEST_GIF_FILE_NAME);
+    propertyMap.Insert(ImageVisual::Property::BATCH_SIZE, 2);
+    propertyMap.Insert(ImageVisual::Property::CACHE_SIZE, 4);
+    propertyMap.Insert(ImageVisual::Property::FRAME_DELAY, 20);
+    propertyMap.Insert(ImageVisual::Property::ALPHA_MASK_URL, url);
+    propertyMap.Insert(DevelImageVisual::Property::MASKING_TYPE, DevelImageVisual::MaskingType::MASKING_ON_RENDERING);
+
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base  visual  = factory.CreateVisual(propertyMap);
+
+    DummyControl        dummyControl = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl    = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+    dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual);
+
+    dummyControl.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+    application.GetScene().Add(dummyControl);
+
+    application.SendNotification();
+    application.Render();
+
+    // load two frame(batch size), load mask image, and do not request two masking
     DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(3), true, TEST_LOCATION);
 
     application.SendNotification();
@@ -1309,6 +1568,10 @@ int UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask03(void)
     dummyControl.Unparent();
   }
   tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(20);
+  application.RunIdles();
   application.SendNotification();
   application.Render(20);
   DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
@@ -1400,6 +1663,10 @@ int UtcDaliAnimatedImageVisualMultiImage01(void)
     dummyControl.Unparent();
   }
   tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(16);
+  application.RunIdles();
   application.SendNotification();
   application.Render(16);
   DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
@@ -1550,6 +1817,10 @@ int UtcDaliAnimatedImageVisualMultiImage02(void)
     dummyControl.Unparent();
   }
   tet_infoline("Test that removing the visual from window deletes all textures");
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(16);
+  application.RunIdles();
   application.SendNotification();
   application.Render(16);
   DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
@@ -1629,6 +1900,10 @@ int UtcDaliAnimatedImageVisualMultiImage03(void)
     dummyControl2.Unparent();
   }
   tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(16);
+  application.RunIdles();
   application.SendNotification();
   application.Render(16);
   DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
@@ -1716,6 +1991,10 @@ int UtcDaliAnimatedImageVisualMultiImage04(void)
   }
 
   tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(16);
+  application.RunIdles();
   application.SendNotification();
   application.Render(16);
   DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
@@ -1772,12 +2051,20 @@ int UtcDaliAnimatedImageVisualMultiImage05(void)
     dummyControl.Unparent();
   }
 
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(16);
+  application.RunIdles();
   application.SendNotification();
   application.Render(16);
   DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
 
   tet_infoline("Test that pending batch of image loads are cancelled instead of uploaded");
   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(4), true, TEST_LOCATION);
+  application.RunIdles();
+  application.SendNotification();
+  application.Render(16);
+  application.RunIdles();
   application.SendNotification();
   application.Render(16);
   DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
@@ -1785,6 +2072,333 @@ int UtcDaliAnimatedImageVisualMultiImage05(void)
   END_TEST;
 }
 
+int UtcDaliAnimatedImageVisualExternalImage01(void)
+{
+  ToolkitTestApplication application;
+  TestGlAbstraction&     gl = application.GetGlAbstraction();
+
+  tet_infoline("Test various cases of url with external image");
+
+  for(int testCase = 0; testCase < 6; testCase++)
+  {
+    ExternalUrlType type     = static_cast<ExternalUrlType>(testCase % 2);
+    ExternalUrlType maskType = static_cast<ExternalUrlType>(testCase / 3);
+
+    const bool useMask = (maskType == ExternalUrlType::EXTERNAL_TEXTURE || maskType == ExternalUrlType::ENCODED_IMAGE_BUFFER);
+
+    ImageUrl imageUrl = ConvertFileToImageUrl(TEST_GIF_FILE_NAME, type);
+    ImageUrl maskImageUrl;
+
+    int preCreatedTextureCount = 0;
+    if(imageUrl.GetUrl()[0] == 'd')
+    {
+      ++preCreatedTextureCount;
+    }
+
+    if(useMask)
+    {
+      maskImageUrl = ConvertFileToImageUrl(TEST_MASK_IMAGE_FILE_NAME, maskType);
+      if(maskImageUrl.GetUrl()[0] == 'd')
+      {
+        ++preCreatedTextureCount;
+      }
+    }
+
+    tet_printf("Test case : %d, image type : %d, mask type : %d. pre-created texture count : %d\n", testCase, type, maskType, preCreatedTextureCount);
+
+    // TODO : Need to fix this UTC
+
+    {
+      Property::Map propertyMap;
+      propertyMap.Insert(Visual::Property::TYPE, Visual::ANIMATED_IMAGE);
+      propertyMap.Insert(ImageVisual::Property::URL, imageUrl.GetUrl());
+      propertyMap.Insert(ImageVisual::Property::BATCH_SIZE, 4);
+      propertyMap.Insert(ImageVisual::Property::CACHE_SIZE, 8);
+      propertyMap.Insert(ImageVisual::Property::FRAME_DELAY, 100);
+      propertyMap.Insert(DevelImageVisual::Property::FRAME_SPEED_FACTOR, 1.5f);
+      if(useMask)
+      {
+        propertyMap.Insert(ImageVisual::Property::ALPHA_MASK_URL, maskImageUrl.GetUrl());
+        propertyMap.Insert(DevelImageVisual::Property::MASKING_TYPE, DevelImageVisual::MaskingType::MASKING_ON_RENDERING);
+      }
+
+      VisualFactory factory = VisualFactory::Get();
+      Visual::Base  visual  = factory.CreateVisual(propertyMap);
+
+      // Expect that a batch of 4 textures has been requested. These will be serially loaded
+      // below.
+
+      DummyControl        dummyControl = DummyControl::New(true);
+      Impl::DummyControl& dummyImpl    = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+      dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual);
+
+      dummyControl.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+      application.GetScene().Add(dummyControl);
+      application.SendNotification();
+      application.Render(16);
+
+      int expectTriggerCount = 0;
+      int expectTextureCount = preCreatedTextureCount;
+      if(imageUrl.GetUrl()[0] == 'e')
+      {
+        ++expectTriggerCount;
+        ++expectTextureCount;
+      }
+
+      if(useMask && maskImageUrl.GetUrl()[0] == 'e')
+      {
+        ++expectTriggerCount;
+        ++expectTextureCount;
+      }
+
+      tet_printf("Ready the visual after the visual is on stage (trigger count : %d, texture count : %d)\n", expectTriggerCount, expectTextureCount);
+      if(expectTriggerCount)
+      {
+        DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(expectTriggerCount), true, TEST_LOCATION);
+      }
+
+      TraceCallStack& textureTrace = gl.GetTextureTrace();
+      textureTrace.Enable(true);
+
+      application.SendNotification();
+      application.Render(16);
+
+      DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), expectTextureCount, TEST_LOCATION);
+      DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
+
+      dummyControl.Unparent();
+    }
+    tet_infoline("Test that removing the visual from stage deletes all textures");
+    imageUrl.Reset();
+    maskImageUrl.Reset();
+
+    application.RunIdles();
+    application.SendNotification();
+    application.Render(16);
+    application.RunIdles();
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedImageVisualExternalMultiImage01(void)
+{
+  ToolkitTestApplication application;
+  TestGlAbstraction&     gl = application.GetGlAbstraction();
+
+  tet_infoline("Test various cases of urls with external images");
+
+  for(int testCase = 0; testCase < 9; testCase++)
+  {
+    ExternalUrlType type     = static_cast<ExternalUrlType>(testCase % 3);
+    ExternalUrlType maskType = static_cast<ExternalUrlType>(testCase / 3);
+
+    const bool useMask = (maskType == ExternalUrlType::EXTERNAL_TEXTURE || maskType == ExternalUrlType::ENCODED_IMAGE_BUFFER);
+
+    Property::Array       urls;
+    std::vector<ImageUrl> imageUrlHolder;
+    CopyExternalUrlsIntoArray(urls, imageUrlHolder, 0, type);
+    int preCreatedTextureCount = 0;
+    for(size_t i = 0u; i < imageUrlHolder.size(); i++)
+    {
+      if(imageUrlHolder[i].GetUrl()[0] == 'd')
+      {
+        ++preCreatedTextureCount;
+      }
+    }
+
+    ImageUrl maskImageUrl;
+    if(useMask)
+    {
+      maskImageUrl = ConvertFileToImageUrl(TEST_MASK_IMAGE_FILE_NAME, maskType);
+      if(maskImageUrl.GetUrl()[0] == 'd')
+      {
+        ++preCreatedTextureCount;
+      }
+    }
+
+    tet_printf("Test case : %d, image type : %d, mask type : %d. pre-created texture count : %d\n", testCase, type, maskType, preCreatedTextureCount);
+
+    // TODO : Need to fix this UTC
+
+    {
+      Property::Map propertyMap;
+      propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE);
+      propertyMap.Insert(ImageVisual::Property::URL, Property::Value(urls));
+      propertyMap.Insert(ImageVisual::Property::BATCH_SIZE, 4);
+      propertyMap.Insert(ImageVisual::Property::CACHE_SIZE, 8);
+      propertyMap.Insert(ImageVisual::Property::FRAME_DELAY, 100);
+      propertyMap.Insert(DevelImageVisual::Property::FRAME_SPEED_FACTOR, 1.5f);
+      if(useMask)
+      {
+        propertyMap.Insert(ImageVisual::Property::ALPHA_MASK_URL, maskImageUrl.GetUrl());
+        propertyMap.Insert(DevelImageVisual::Property::MASKING_TYPE, DevelImageVisual::MaskingType::MASKING_ON_RENDERING);
+      }
+
+      VisualFactory factory = VisualFactory::Get();
+      Visual::Base  visual  = factory.CreateVisual(propertyMap);
+
+      // Expect that a batch of 4 textures has been requested. These will be serially loaded
+      // below.
+
+      DummyControl        dummyControl = DummyControl::New(true);
+      Impl::DummyControl& dummyImpl    = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+      dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual);
+
+      dummyControl.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+      application.GetScene().Add(dummyControl);
+      application.SendNotification();
+      application.Render(16);
+
+      int expectTriggerCount = 0;
+      int expectTextureCount = preCreatedTextureCount;
+      for(int i = 0; i < 4; i++)
+      {
+        if(imageUrlHolder[(i % imageUrlHolder.size())].GetUrl()[0] == 'e')
+        {
+          ++expectTriggerCount;
+          ++expectTextureCount;
+        }
+      }
+
+      if(useMask && maskImageUrl.GetUrl()[0] == 'e')
+      {
+        ++expectTriggerCount;
+        ++expectTextureCount;
+      }
+
+      tet_printf("Ready the visual after the visual is on stage (trigger count : %d, texture count : %d)\n", expectTriggerCount, expectTextureCount);
+      if(expectTriggerCount)
+      {
+        DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(expectTriggerCount), true, TEST_LOCATION);
+      }
+
+      tet_printf("Test that a timer has been started\n");
+      DALI_TEST_EQUALS(Test::GetTimerCount(), 1, TEST_LOCATION);
+
+      TraceCallStack& textureTrace = gl.GetTextureTrace();
+      textureTrace.Enable(true);
+
+      application.SendNotification();
+      application.Render(16);
+
+      DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), expectTextureCount, TEST_LOCATION);
+      DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
+
+      tet_printf("Test that after 1 tick, and file loads completed, that we have 7 textures\n");
+      Test::EmitGlobalTimerSignal();
+
+      expectTriggerCount = 0;
+      for(int i = 0; i < 1; i++)
+      {
+        if(imageUrlHolder[(i % imageUrlHolder.size())].GetUrl()[0] == 'e')
+        {
+          --expectTextureCount;
+        }
+      }
+      for(int i = 4; i < 8; i++)
+      {
+        if(imageUrlHolder[(i % imageUrlHolder.size())].GetUrl()[0] == 'e')
+        {
+          ++expectTriggerCount;
+          ++expectTextureCount;
+        }
+      }
+
+      // Expect the second batch has been requested
+      tet_printf("Expect the second batch has been requested (trigger count : %d, texture count : %d)\n", expectTriggerCount, expectTextureCount);
+      if(expectTriggerCount)
+      {
+        DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(expectTriggerCount), true, TEST_LOCATION);
+      }
+
+      application.SendNotification();
+      application.Render(16);
+      DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), expectTextureCount, TEST_LOCATION);
+
+      for(int i = 1; i < 2; i++)
+      {
+        if(imageUrlHolder[(i % imageUrlHolder.size())].GetUrl()[0] == 'e')
+        {
+          --expectTextureCount;
+        }
+      }
+      tet_printf("Test that after 2 ticks that we have 6 textures (texture count : %d)\n", expectTextureCount);
+
+      Test::EmitGlobalTimerSignal();
+      application.SendNotification();
+      application.Render(16);
+      DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), expectTextureCount, TEST_LOCATION);
+
+      expectTriggerCount = 0;
+      for(int i = 8; i < 10; i++)
+      {
+        if(imageUrlHolder[(i % imageUrlHolder.size())].GetUrl()[0] == 'e')
+        {
+          ++expectTriggerCount;
+          ++expectTextureCount;
+        }
+      }
+      tet_printf("And that at least 2 textures were requested (trigger count : %d, texture count : %d)\n", expectTriggerCount, expectTextureCount);
+      if(expectTriggerCount)
+      {
+        DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(expectTriggerCount), true, TEST_LOCATION);
+      }
+      application.SendNotification();
+      application.Render(16);
+      DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), expectTextureCount, TEST_LOCATION);
+
+      for(int i = 2; i < 3; i++)
+      {
+        if(imageUrlHolder[(i % imageUrlHolder.size())].GetUrl()[0] == 'e')
+        {
+          --expectTextureCount;
+        }
+      }
+      tet_printf("Test that after 3rd tick that we have 7 textures and 1 request (texture count : %d)\n", expectTextureCount);
+      Test::EmitGlobalTimerSignal();
+      application.SendNotification();
+      application.Render(16);
+      DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), expectTextureCount, TEST_LOCATION);
+
+      expectTriggerCount = 0;
+      for(int i = 10; i < 11; i++)
+      {
+        if(imageUrlHolder[(i % imageUrlHolder.size())].GetUrl()[0] == 'e')
+        {
+          ++expectTriggerCount;
+          ++expectTextureCount;
+        }
+      }
+      if(expectTriggerCount)
+      {
+        DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(expectTriggerCount), true, TEST_LOCATION);
+      }
+      application.SendNotification();
+      application.Render(16);
+      DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), expectTextureCount, TEST_LOCATION);
+
+      dummyControl.Unparent();
+    }
+    tet_infoline("Test that removing the visual from stage deletes all textures");
+    imageUrlHolder.clear();
+    maskImageUrl.Reset();
+
+    application.RunIdles();
+    application.SendNotification();
+    application.Render(16);
+    application.RunIdles();
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION);
+  }
+
+  END_TEST;
+}
+
 namespace
 {
 void TestLoopCount(ToolkitTestApplication& application, DummyControl& dummyControl, uint16_t frameCount, uint16_t loopCount, const char* location)
index 2d30bbf792f990887ca7e8f397fa992feea5708e..5007ec3e25202a225cc0b0f6593e68baf56bb725 100644 (file)
@@ -654,7 +654,7 @@ int UtcDaliImageVisualWithPixelDataPreMultipliedAlpha(void)
   END_TEST;
 }
 
-int UtcDaliImageVisualWithPixelDataMasking(void)
+int UtcDaliImageVisualWithPixelDataMasking01(void)
 {
   ToolkitTestApplication application;
   tet_infoline("Load external texture with mask");
@@ -672,7 +672,7 @@ int UtcDaliImageVisualWithPixelDataMasking(void)
 
   DALI_TEST_CHECK(pixelData);
 
-  ImageUrl    imageUrl = Dali::Toolkit::Image::GenerateUrl(pixelData, true);
+  ImageUrl    imageUrl = Dali::Toolkit::Image::GenerateUrl(pixelData);
   std::string url      = imageUrl.GetUrl();
 
   VisualFactory factory = VisualFactory::Get();
@@ -705,6 +705,18 @@ int UtcDaliImageVisualWithPixelDataMasking(void)
   DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
   DALI_TEST_EQUALS(actor.IsResourceReady(), true, TEST_LOCATION);
 
+  // Update result map after load completed.
+  visual.CreatePropertyMap(testMap);
+
+  Renderer renderer = actor.GetRendererAt(0);
+
+  //Check visual property
+  DALI_TEST_EQUALS(*testMap.Find(Visual::Property::PREMULTIPLIED_ALPHA), Property::Value(false), TEST_LOCATION);
+
+  // Check whether preMultipliedAlpha is false.
+  auto preMultipliedAlpha = renderer.GetProperty<bool>(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA);
+  DALI_TEST_EQUALS(preMultipliedAlpha, false, TEST_LOCATION);
+
   dummyImpl.UnregisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1);
   DALI_TEST_EQUALS(actor.GetRendererCount(), 0u, TEST_LOCATION);
 
@@ -762,6 +774,9 @@ int UtcDaliImageVisualWithPixelDataMasking02(void)
   DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
   DALI_TEST_EQUALS(actor.IsResourceReady(), true, TEST_LOCATION);
 
+  // Update result map after load completed.
+  visual.CreatePropertyMap(testMap);
+
   Renderer renderer = actor.GetRendererAt(0);
 
   //Check visual property
@@ -777,6 +792,205 @@ int UtcDaliImageVisualWithPixelDataMasking02(void)
   END_TEST;
 }
 
+int UtcDaliImageVisualWithPixelDataMasking03(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("Load external texture with invalid mask file");
+
+  TestGlAbstraction& gl           = application.GetGlAbstraction();
+  TraceCallStack&    textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  uint32_t width(64);
+  uint32_t height(64);
+  uint32_t bufferSize = width * height * Pixel::GetBytesPerPixel(Pixel::RGBA8888);
+
+  uint8_t*  buffer    = reinterpret_cast<uint8_t*>(malloc(bufferSize));
+  PixelData pixelData = PixelData::New(buffer, bufferSize, width, height, Pixel::RGBA8888, PixelData::FREE);
+
+  DALI_TEST_CHECK(pixelData);
+
+  ImageUrl    imageUrl = Dali::Toolkit::Image::GenerateUrl(pixelData);
+  std::string url      = imageUrl.GetUrl();
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK(factory);
+
+  Property::Map propertyMap;
+  propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
+  propertyMap.Insert(ImageVisual::Property::URL, url);
+  propertyMap.Insert(ImageVisual::Property::ALPHA_MASK_URL, TEST_INVALID_FILE_NAME);
+
+  Visual::Base visual = factory.CreateVisual(propertyMap);
+  DALI_TEST_CHECK(visual);
+
+  Property::Map testMap;
+  visual.CreatePropertyMap(testMap);
+  DALI_TEST_EQUALS(*testMap.Find(ImageVisual::Property::ALPHA_MASK_URL), Property::Value(TEST_INVALID_FILE_NAME), TEST_LOCATION);
+
+  DummyControl      actor     = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual);
+
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 0u, TEST_LOCATION);
+
+  application.GetScene().Add(actor);
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(actor.IsResourceReady(), true, TEST_LOCATION);
+
+  // Update result map after load completed.
+  visual.CreatePropertyMap(testMap);
+
+  Renderer renderer = actor.GetRendererAt(0);
+
+  //Check visual property
+  DALI_TEST_EQUALS(*testMap.Find(Visual::Property::PREMULTIPLIED_ALPHA), Property::Value(false), TEST_LOCATION);
+
+  // Check whether preMultipliedAlpha is false.
+  auto preMultipliedAlpha = renderer.GetProperty<bool>(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA);
+  DALI_TEST_EQUALS(preMultipliedAlpha, false, TEST_LOCATION);
+
+  dummyImpl.UnregisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1);
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 0u, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualWithPixelDataMasking04(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("Load external texture with external texture mask");
+
+  TestGlAbstraction& gl           = application.GetGlAbstraction();
+  TraceCallStack&    textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  uint32_t width(64);
+  uint32_t height(64);
+  uint32_t bufferSize = width * height * Pixel::GetBytesPerPixel(Pixel::RGBA8888);
+
+  uint8_t*  buffer    = reinterpret_cast<uint8_t*>(malloc(bufferSize));
+  PixelData pixelData = PixelData::New(buffer, bufferSize, width, height, Pixel::RGBA8888, PixelData::FREE);
+
+  DALI_TEST_CHECK(pixelData);
+
+  ImageUrl    imageUrl = Dali::Toolkit::Image::GenerateUrl(pixelData);
+  std::string url      = imageUrl.GetUrl();
+
+  uint8_t*    anotherBuffer = reinterpret_cast<uint8_t*>(malloc(bufferSize));
+  PixelData   maskPixelData = PixelData::New(anotherBuffer, bufferSize, width, height, Pixel::RGBA8888, PixelData::FREE);
+  ImageUrl    maskImageUrl  = Dali::Toolkit::Image::GenerateUrl(maskPixelData);
+  std::string maskUrl       = maskImageUrl.GetUrl();
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK(factory);
+
+  Property::Map propertyMap;
+  propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
+  propertyMap.Insert(ImageVisual::Property::URL, url);
+  propertyMap.Insert(ImageVisual::Property::ALPHA_MASK_URL, maskUrl);
+
+  Visual::Base visual = factory.CreateVisual(propertyMap);
+  DALI_TEST_CHECK(visual);
+
+  Property::Map testMap;
+  visual.CreatePropertyMap(testMap);
+  DALI_TEST_EQUALS(*testMap.Find(ImageVisual::Property::ALPHA_MASK_URL), Property::Value(maskUrl), TEST_LOCATION);
+
+  DummyControl      actor     = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual);
+
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 0u, TEST_LOCATION);
+
+  application.GetScene().Add(actor);
+  application.SendNotification();
+  application.Render(16);
+
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(actor.IsResourceReady(), true, TEST_LOCATION);
+
+  // Update result map after load completed.
+  visual.CreatePropertyMap(testMap);
+
+  Renderer renderer = actor.GetRendererAt(0);
+
+  //Check visual property
+  DALI_TEST_EQUALS(*testMap.Find(Visual::Property::PREMULTIPLIED_ALPHA), Property::Value(false), TEST_LOCATION);
+
+  // Check whether preMultipliedAlpha is false.
+  auto preMultipliedAlpha = renderer.GetProperty<bool>(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA);
+  DALI_TEST_EQUALS(preMultipliedAlpha, false, TEST_LOCATION);
+
+  dummyImpl.UnregisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1);
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 0u, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualWithPixelDataMasking05(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("Load image with external texture mask");
+
+  TestGlAbstraction& gl           = application.GetGlAbstraction();
+  TraceCallStack&    textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  uint32_t width(64);
+  uint32_t height(64);
+  uint32_t bufferSize = width * height * Pixel::GetBytesPerPixel(Pixel::RGBA8888);
+
+  uint8_t*  buffer    = reinterpret_cast<uint8_t*>(malloc(bufferSize));
+  PixelData pixelData = PixelData::New(buffer, bufferSize, width, height, Pixel::RGBA8888, PixelData::FREE);
+
+  DALI_TEST_CHECK(pixelData);
+
+  ImageUrl    imageUrl = Dali::Toolkit::Image::GenerateUrl(pixelData);
+  std::string url      = imageUrl.GetUrl();
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK(factory);
+
+  Property::Map propertyMap;
+  propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
+  propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME);
+  propertyMap.Insert(ImageVisual::Property::ALPHA_MASK_URL, url);
+
+  Visual::Base visual = factory.CreateVisual(propertyMap);
+  DALI_TEST_CHECK(visual);
+
+  Property::Map testMap;
+  visual.CreatePropertyMap(testMap);
+  DALI_TEST_EQUALS(*testMap.Find(ImageVisual::Property::ALPHA_MASK_URL), Property::Value(url), TEST_LOCATION);
+
+  DummyControl      actor     = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual);
+
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 0u, TEST_LOCATION);
+
+  application.GetScene().Add(actor);
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(actor.IsResourceReady(), true, TEST_LOCATION);
+
+  dummyImpl.UnregisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1);
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 0u, TEST_LOCATION);
+
+  END_TEST;
+}
+
 int UtcDaliImageVisualWithPixelDataMaskingSynchronously(void)
 {
   ToolkitTestApplication application;
@@ -791,7 +1005,7 @@ int UtcDaliImageVisualWithPixelDataMaskingSynchronously(void)
 
   DALI_TEST_CHECK(pixelData);
 
-  ImageUrl    imageUrl = Dali::Toolkit::Image::GenerateUrl(pixelData, true);
+  ImageUrl    imageUrl = Dali::Toolkit::Image::GenerateUrl(pixelData);
   std::string url      = imageUrl.GetUrl();
 
   VisualFactory factory = VisualFactory::Get();
index 868d57da36d14c0d2ce1ef110d4b94cbcf93dcc8..89814cbc98368475e8865f2fc17ef50d33b36f35 100644 (file)
@@ -118,7 +118,12 @@ TextureCacheManager::~TextureCacheManager()
 
 VisualUrl TextureCacheManager::GetVisualUrl(const TextureCacheManager::TextureId textureId)
 {
-  VisualUrl         visualUrl("");
+  VisualUrl visualUrl("");
+  if(textureId == INVALID_TEXTURE_ID)
+  {
+    return visualUrl;
+  }
+
   TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<uint32_t>(textureId)]);
 
   switch(static_cast<TextureCacheIndexType>(cacheIndex.detailValue.type))
@@ -157,7 +162,12 @@ VisualUrl TextureCacheManager::GetVisualUrl(const TextureCacheManager::TextureId
 
 TextureCacheManager::LoadState TextureCacheManager::GetTextureState(const TextureCacheManager::TextureId textureId)
 {
-  LoadState         loadState  = TextureCacheManager::LoadState::NOT_STARTED;
+  LoadState loadState = TextureCacheManager::LoadState::NOT_STARTED;
+  if(textureId == INVALID_TEXTURE_ID)
+  {
+    return loadState;
+  }
+
   TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<uint32_t>(textureId)]);
 
   switch(static_cast<TextureCacheIndexType>(cacheIndex.detailValue.type))
@@ -170,7 +180,8 @@ TextureCacheManager::LoadState TextureCacheManager::GetTextureState(const Textur
     }
     case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE:
     {
-      loadState = LoadState::UPLOADED;
+      ExternalTextureInfo& cachedExternalTextureInfo(mExternalTextures[cacheIndex.GetIndex()]);
+      loadState = cachedExternalTextureInfo.textureSet ? LoadState::UPLOADED : LoadState::LOAD_FAILED;
       break;
     }
     default:
@@ -182,23 +193,15 @@ TextureCacheManager::LoadState TextureCacheManager::GetTextureState(const Textur
   return loadState;
 }
 
-TextureCacheManager::LoadState TextureCacheManager::GetTextureStateInternal(const TextureCacheManager::TextureId textureId)
+Texture TextureCacheManager::GetTexture(const TextureCacheManager::TextureId textureId, const uint32_t textureIndex)
 {
-  LoadState         loadState  = TextureCacheManager::LoadState::NOT_STARTED;
-  TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
-  if(cacheIndex != INVALID_CACHE_INDEX)
+  Texture texture; // empty handle
+  if(textureId == INVALID_TEXTURE_ID)
   {
-    TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
-    loadState = cachedTextureInfo.loadState;
+    return texture;
   }
 
-  return loadState;
-}
-
-Texture TextureCacheManager::GetTexture(const TextureCacheManager::TextureId textureId, const uint32_t textureIndex)
-{
-  Texture           texture; // empty handle
-  TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
+  TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<uint32_t>(textureId)]);
 
   switch(static_cast<TextureCacheIndexType>(cacheIndex.detailValue.type))
   {
@@ -211,6 +214,15 @@ Texture TextureCacheManager::GetTexture(const TextureCacheManager::TextureId tex
       }
       break;
     }
+    case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE:
+    {
+      ExternalTextureInfo& cachedExternalTextureInfo(mExternalTextures[cacheIndex.GetIndex()]);
+      if(cachedExternalTextureInfo.textureSet && textureIndex < static_cast<uint32_t>(cachedExternalTextureInfo.textureSet.GetTextureCount()))
+      {
+        texture = cachedExternalTextureInfo.textureSet.GetTexture(textureIndex);
+      }
+      break;
+    }
     default:
     {
       break;
@@ -244,10 +256,9 @@ EncodedImageBuffer TextureCacheManager::GetEncodedImageBuffer(const VisualUrl& u
   EncodedImageBuffer encodedImageBuffer; // empty handle
   if(url.IsValid() && VisualUrl::BUFFER == url.GetProtocolType())
   {
-    std::string location = url.GetLocationWithoutExtension();
-    if(location.size() > 0u)
+    TextureId bufferId = INVALID_TEXTURE_ID;
+    if(url.GetLocationAsInteger(bufferId) && bufferId != INVALID_TEXTURE_ID)
     {
-      TextureId bufferId = std::stoi(location);
       return GetEncodedImageBuffer(bufferId);
     }
   }
@@ -308,21 +319,20 @@ TextureSet TextureCacheManager::RemoveExternalTexture(const VisualUrl& url)
     if(VisualUrl::TEXTURE == url.GetProtocolType())
     {
       // get the location from the Url
-      std::string location = url.GetLocation();
-      if(location.size() > 0u)
+      TextureId externalTextureId = INVALID_TEXTURE_ID;
+      if(url.GetLocationAsInteger(externalTextureId) && externalTextureId != INVALID_TEXTURE_ID)
       {
-        TextureId textureId = std::stoi(location);
-        removeTextureIndex  = GetCacheIndexFromExternalTextureId(textureId);
+        removeTextureIndex = GetCacheIndexFromExternalTextureId(externalTextureId);
         if(removeTextureIndex != INVALID_CACHE_INDEX)
         {
           ExternalTextureInfo& textureInfo(mExternalTextures[removeTextureIndex.GetIndex()]);
-          DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::RemoveExternalTexture(url:%s) textureId:%d reference:%d\n", url.GetUrl().c_str(), textureId, static_cast<int>(textureInfo.referenceCount));
+          DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::RemoveExternalTexture(url:%s) textureId:%d reference:%d\n", url.GetUrl().c_str(), externalTextureId, static_cast<int>(textureInfo.referenceCount));
           textureSet = textureInfo.textureSet;
           if(--(textureInfo.referenceCount) <= 0)
           {
             removeTextureInfo = true;
             // id life is finished. Remove it at converter
-            mTextureIdConverter.Remove(textureId);
+            mTextureIdConverter.Remove(externalTextureId);
           }
         }
       }
@@ -348,11 +358,10 @@ EncodedImageBuffer TextureCacheManager::RemoveEncodedImageBuffer(const VisualUrl
     if(VisualUrl::BUFFER == url.GetProtocolType())
     {
       // get the location from the Url
-      std::string location = url.GetLocationWithoutExtension();
-      if(location.size() > 0u)
+      TextureId bufferId = INVALID_TEXTURE_ID;
+      if(url.GetLocationAsInteger(bufferId) && bufferId != INVALID_TEXTURE_ID)
       {
-        TextureId bufferId = std::stoi(location);
-        removeBufferIndex  = GetCacheIndexFromEncodedImageBufferId(bufferId);
+        removeBufferIndex = GetCacheIndexFromEncodedImageBufferId(bufferId);
 
         if(removeBufferIndex != INVALID_CACHE_INDEX)
         {
@@ -386,11 +395,10 @@ void TextureCacheManager::UseExternalResource(const VisualUrl& url)
 {
   if(VisualUrl::TEXTURE == url.GetProtocolType())
   {
-    std::string location = url.GetLocation();
-    if(location.size() > 0u)
+    TextureId externalTextureId = INVALID_TEXTURE_ID;
+    if(url.GetLocationAsInteger(externalTextureId) && externalTextureId != INVALID_TEXTURE_ID)
     {
-      TextureId         id         = std::stoi(location);
-      TextureCacheIndex cacheIndex = GetCacheIndexFromExternalTextureId(id);
+      TextureCacheIndex cacheIndex = GetCacheIndexFromExternalTextureId(externalTextureId);
       if(cacheIndex != INVALID_CACHE_INDEX)
       {
         ExternalTextureInfo& textureInfo(mExternalTextures[cacheIndex.GetIndex()]);
@@ -403,11 +411,10 @@ void TextureCacheManager::UseExternalResource(const VisualUrl& url)
   }
   else if(VisualUrl::BUFFER == url.GetProtocolType())
   {
-    std::string location = url.GetLocationWithoutExtension();
-    if(location.size() > 0u)
+    TextureId encodedImageBufferId = INVALID_TEXTURE_ID;
+    if(url.GetLocationAsInteger(encodedImageBufferId) && encodedImageBufferId != INVALID_TEXTURE_ID)
     {
-      TextureId         id         = std::stoi(location);
-      TextureCacheIndex cacheIndex = GetCacheIndexFromEncodedImageBufferId(id);
+      TextureCacheIndex cacheIndex = GetCacheIndexFromEncodedImageBufferId(encodedImageBufferId);
       if(cacheIndex != INVALID_CACHE_INDEX)
       {
         EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[cacheIndex.GetIndex()]);
index 10bf73df380d8ea24eb0cc567a9156ca49ce0a6d..708b2a4d691fed245a8031d18aa337c8fe200372 100644 (file)
@@ -107,15 +107,6 @@ public:
    */
   TextureCacheManager::LoadState GetTextureState(const TextureCacheManager::TextureId textureId);
 
-  /**
-   * @brief Get the current state of a texture
-   * @note This API doesn't consider external & encodedimagebuffer.
-   * @param[in] textureId The texture id to query
-   * @return The loading state if the texture is valid, or NOT_STARTED if the textureId
-   * is not valid.
-   */
-  TextureCacheManager::LoadState GetTextureStateInternal(const TextureCacheManager::TextureId textureId);
-
   /**
    * @brief Get the associated texture set if the texture id is valid
    * @param[in] textureId The texture Id to look up
index 9030c5a64c1671ed762cade59be56ab964bffa3a..dd597bb3e5efbec19f0f3c77e0deb57e250e4625 100644 (file)
@@ -65,6 +65,13 @@ Debug::Filter* gTextureManagerLogFilter = Debug::Filter::New(Debug::NoLogging, f
   loadState == TextureManagerType::LoadState::MASK_CANCELLED   ? "MASK_CANCELLED"   : \
   loadState == TextureManagerType::LoadState::LOAD_FAILED      ? "LOAD_FAILED"      : \
                                                                  "Unknown"
+
+#define GET_STORAGE_TYPE_STRING(storageType) \
+  storageType == TextureManagerType::StorageType::KEEP_PIXEL_BUFFER   ? "KEEP_PIXEL_BUFFER"   : \
+  storageType == TextureManagerType::StorageType::RETURN_PIXEL_BUFFER ? "RETURN_PIXEL_BUFFER" : \
+  storageType == TextureManagerType::StorageType::KEEP_TEXTURE        ? "KEEP_TEXTURE"        : \
+  storageType == TextureManagerType::StorageType::UPLOAD_TO_TEXTURE   ? "UPLOAD_TO_TEXTURE"   : \
+                                                                        "Unknown"
 // clang-format on
 #endif
 
@@ -134,8 +141,29 @@ TextureSet TextureManager::LoadAnimatedImageTexture(
 {
   TextureSet textureSet;
 
+  TextureId alphaMaskId        = INVALID_TEXTURE_ID;
+  float     contentScaleFactor = 1.0f;
+  bool      cropToMask         = false;
+  if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
+  {
+    const bool preappliedMasking = maskInfo->mPreappliedMasking && (VisualUrl::TEXTURE != url.GetProtocolType());
+    maskInfo->mPreappliedMasking = preappliedMasking;
+
+    maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, preappliedMasking ? TextureManager::StorageType::KEEP_PIXEL_BUFFER : TextureManager::StorageType::KEEP_TEXTURE, synchronousLoading);
+    alphaMaskId            = maskInfo->mAlphaMaskId;
+    if(maskInfo && preappliedMasking)
+    {
+      contentScaleFactor = maskInfo->mContentScaleFactor;
+      cropToMask         = maskInfo->mCropToMask;
+    }
+  }
+
   if(synchronousLoading)
   {
+    // TODO : Please remove this duplicated codes.
+    // Since we don't cache sync loaded texture.
+    // But cannot remove it since AnimatedImageVisual didn't consider sync load cached case.
+    // It should be fixed soon.
     Devel::PixelBuffer pixelBuffer;
     if(animatedImageLoading)
     {
@@ -148,26 +176,46 @@ TextureSet TextureManager::LoadAnimatedImageTexture(
     else
     {
       Texture maskTexture;
-      if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
+      if(alphaMaskId != INVALID_TEXTURE_ID)
       {
-        Devel::PixelBuffer maskPixelBuffer = LoadImageFromFile(maskInfo->mAlphaMaskUrl.GetUrl(), desiredSize, fittingMode, samplingMode, true);
-        if(maskPixelBuffer)
+        TextureCacheIndex maskCacheIndex = mTextureCacheManager.GetCacheIndexFromId(alphaMaskId);
+        if(maskCacheIndex != INVALID_CACHE_INDEX)
         {
-          if(!maskInfo->mPreappliedMasking)
+          TextureInfo& maskTextureInfo(mTextureCacheManager[maskCacheIndex]);
+          if(maskTextureInfo.storageType == TextureManager::StorageType::UPLOAD_TO_TEXTURE ||
+             maskTextureInfo.storageType == TextureManager::StorageType::KEEP_TEXTURE)
           {
-            PixelData maskPixelData = Devel::PixelBuffer::Convert(maskPixelBuffer); // takes ownership of buffer
-            maskTexture             = Texture::New(Dali::TextureType::TEXTURE_2D, maskPixelData.GetPixelFormat(), maskPixelData.GetWidth(), maskPixelData.GetHeight());
-            maskTexture.Upload(maskPixelData);
+            if(maskTextureInfo.textures.size() > TEXTURE_INDEX)
+            {
+              maskTexture = maskTextureInfo.textures[TEXTURE_INDEX];
+            }
+            else
+            {
+              DALI_LOG_ERROR("TextureManager::LoadAnimatedImageTexture: Synchronous mask image loading is failed\n");
+            }
           }
-          else
+          else if(maskTextureInfo.storageType == TextureManager::StorageType::KEEP_PIXEL_BUFFER)
           {
-            pixelBuffer.ApplyMask(maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask);
+            Devel::PixelBuffer maskPixelBuffer = maskTextureInfo.pixelBuffer;
+            if(maskPixelBuffer)
+            {
+              if(!maskInfo->mPreappliedMasking)
+              {
+                PixelData maskPixelData = Devel::PixelBuffer::Convert(maskPixelBuffer); // takes ownership of buffer
+                maskTexture             = Texture::New(Dali::TextureType::TEXTURE_2D, maskPixelData.GetPixelFormat(), maskPixelData.GetWidth(), maskPixelData.GetHeight());
+                maskTexture.Upload(maskPixelData);
+              }
+              else
+              {
+                pixelBuffer.ApplyMask(maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask);
+              }
+            }
+            else
+            {
+              DALI_LOG_ERROR("TextureManager::LoadAnimatedImageTexture: Synchronous mask image loading is failed\n");
+            }
           }
         }
-        else
-        {
-          DALI_LOG_ERROR("TextureManager::LoadAnimatedImageTexture: Synchronous mask image loading is failed\n");
-        }
       }
 
       if(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD)
@@ -176,38 +224,21 @@ TextureSet TextureManager::LoadAnimatedImageTexture(
       }
 
       PixelData pixelData = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
-      if(!textureSet)
+      Texture   texture   = Texture::New(Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight());
+      texture.Upload(pixelData);
+      textureSet = TextureSet::New();
+      textureSet.SetTexture(TEXTURE_INDEX, texture);
+      if(maskTexture)
       {
-        Texture texture = Texture::New(Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight());
-        texture.Upload(pixelData);
-        textureSet = TextureSet::New();
-        textureSet.SetTexture(TEXTURE_INDEX, texture);
-        if(maskTexture)
-        {
-          textureSet.SetTexture(MASK_TEXTURE_INDEX, maskTexture);
-        }
+        textureSet.SetTexture(MASK_TEXTURE_INDEX, maskTexture);
       }
     }
   }
   else
   {
-    TextureId alphaMaskId        = INVALID_TEXTURE_ID;
-    float     contentScaleFactor = 1.0f;
-    bool      cropToMask         = false;
-    if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
-    {
-      maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, maskInfo->mPreappliedMasking ? TextureManager::StorageType::KEEP_PIXEL_BUFFER : TextureManager::StorageType::KEEP_TEXTURE);
-      alphaMaskId            = maskInfo->mAlphaMaskId;
-      if(maskInfo->mPreappliedMasking)
-      {
-        contentScaleFactor = maskInfo->mContentScaleFactor;
-        cropToMask         = maskInfo->mCropToMask;
-      }
-    }
-
     textureId = RequestLoadInternal(url, alphaMaskId, textureId, contentScaleFactor, desiredSize, fittingMode, samplingMode, cropToMask, TextureManager::StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiplyOnLoad, animatedImageLoading, frameIndex, false);
 
-    TextureManager::LoadState loadState = mTextureCacheManager.GetTextureStateInternal(textureId);
+    TextureManager::LoadState loadState = mTextureCacheManager.GetTextureState(textureId);
     if(loadState == TextureManager::LoadState::UPLOADED)
     {
       // LoadComplete has already been called - keep the same texture set
@@ -285,170 +316,134 @@ TextureSet TextureManager::LoadTexture(
 
   if(VisualUrl::TEXTURE == url.GetProtocolType())
   {
-    std::string location = url.GetLocation();
-    if(location.size() > 0u)
+    // Ensure that external texture don't allow atlasing.
+    atlasingStatus = false;
+  }
+
+  // For Atlas
+  if(synchronousLoading && atlasingStatus)
+  {
+    const bool synchronousAtlasAvaliable = (desiredSize != ImageDimensions() || url.IsLocalResource()) ? imageAtlasManager->CheckAtlasAvailable(url, desiredSize)
+                                                                                                       : false;
+    if(synchronousAtlasAvaliable)
     {
-      TextureId id                  = std::stoi(location);
-      auto      externalTextureInfo = mTextureCacheManager.GetExternalTextureInfo(id);
-      if(externalTextureInfo.textureSet)
+      std::vector<Devel::PixelBuffer> pixelBuffers;
+      LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection, false, pixelBuffers);
+
+      if(!pixelBuffers.empty() && maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
       {
-        if(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD)
+        std::vector<Devel::PixelBuffer> maskPixelBuffers;
+        LoadImageSynchronously(maskInfo->mAlphaMaskUrl, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true, false, maskPixelBuffers);
+        if(!maskPixelBuffers.empty())
         {
-          // Change preMultiplyOnLoad value so make caller determine to preMultiplyAlpha or not.
-          // TODO : Should we seperate input and output value?
-          preMultiplyOnLoad = externalTextureInfo.preMultiplied ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+          pixelBuffers[0].ApplyMask(maskPixelBuffers[0], maskInfo->mContentScaleFactor, maskInfo->mCropToMask);
         }
+      }
 
-        TextureId alphaMaskId = INVALID_TEXTURE_ID;
-        if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
-        {
-          maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, TextureManager::StorageType::KEEP_TEXTURE, synchronousLoading);
-          alphaMaskId            = maskInfo->mAlphaMaskId;
-
-          // Create new textureId. this textureId is not same as location
-          textureId = RequestLoad(url, alphaMaskId, textureId, 1.0f, desiredSize, fittingMode, samplingMode, false, textureObserver, orientationCorrection, reloadPolicy, preMultiplyOnLoad, synchronousLoading);
+      PixelData data;
+      if(!pixelBuffers.empty())
+      {
+        PreMultiply(pixelBuffers[0], preMultiplyOnLoad);
+        data = Devel::PixelBuffer::Convert(pixelBuffers[0]); // takes ownership of buffer
 
-          TextureManager::LoadState loadState = mTextureCacheManager.GetTextureStateInternal(textureId);
-          if(loadState == TextureManager::LoadState::UPLOADED)
+        if(data)
+        {
+          textureSet = imageAtlasManager->Add(textureRect, data);
+          if(textureSet)
           {
-            textureSet = GetTextureSet(textureId);
+            textureRectSize.SetWidth(data.GetWidth());
+            textureRectSize.SetHeight(data.GetHeight());
           }
         }
         else
         {
-          // TextureId is same as location
-          textureId = id;
-
-          textureSet = TextureSet::New();
-          textureSet.SetTexture(TEXTURE_INDEX, externalTextureInfo.textureSet.GetTexture(TEXTURE_INDEX));
+          DALI_LOG_ERROR("TextureManager::LoadTexture: Synchronous Texture loading with atlasing is failed.\n");
         }
       }
-    }
-  }
-  else
-  {
-    // For Atlas
-    if(synchronousLoading && atlasingStatus)
-    {
-      const bool synchronousAtlasAvaliable = (desiredSize != ImageDimensions() || url.IsLocalResource()) ? imageAtlasManager->CheckAtlasAvailable(url, desiredSize)
-                                                                                                         : false;
-      if(synchronousAtlasAvaliable)
+      if(!textureSet)
       {
-        std::vector<Devel::PixelBuffer> pixelBuffers;
-        LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection, false, pixelBuffers);
-
-        if(!pixelBuffers.empty() && maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
-        {
-          std::vector<Devel::PixelBuffer> maskPixelBuffers;
-          LoadImageSynchronously(maskInfo->mAlphaMaskUrl, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true, false, maskPixelBuffers);
-          if(!maskPixelBuffers.empty())
-          {
-            pixelBuffers[0].ApplyMask(maskPixelBuffers[0], maskInfo->mContentScaleFactor, maskInfo->mCropToMask);
-          }
-        }
-
-        PixelData data;
-        if(!pixelBuffers.empty())
-        {
-          PreMultiply(pixelBuffers[0], preMultiplyOnLoad);
-          data = Devel::PixelBuffer::Convert(pixelBuffers[0]); // takes ownership of buffer
-
-          if(data)
-          {
-            textureSet = imageAtlasManager->Add(textureRect, data);
-            if(textureSet)
-            {
-              textureRectSize.SetWidth(data.GetWidth());
-              textureRectSize.SetHeight(data.GetHeight());
-            }
-          }
-          else
-          {
-            DALI_LOG_ERROR("TextureManager::LoadTexture: Synchronous Texture loading with atlasing is failed.\n");
-          }
-        }
-        if(!textureSet)
-        {
-          atlasingStatus = false;
-        }
+        atlasingStatus = false;
       }
     }
+  }
 
-    if(!textureSet)
+  if(!textureSet)
+  {
+    loadingStatus = true;
+    // Atlas manager can chage desired size when it is set by 0,0.
+    // We should store into textureRectSize only if atlasing successed.
+    // So copy inputed desiredSize, and replace value into textureRectSize only if atlasing success.
+    Dali::ImageDimensions atlasDesiredSize = desiredSize;
+    if(atlasingStatus)
     {
-      loadingStatus = true;
-      // Atlas manager can chage desired size when it is set by 0,0.
-      // We should store into textureRectSize only if atlasing successed.
-      // So copy inputed desiredSize, and replace value into textureRectSize only if atlasing success.
-      Dali::ImageDimensions atlasDesiredSize = desiredSize;
-      if(atlasingStatus)
+      if(url.IsBufferResource())
       {
-        if(url.IsBufferResource())
-        {
-          const EncodedImageBuffer& encodedImageBuffer = GetEncodedImageBuffer(url.GetUrl());
-          if(encodedImageBuffer)
-          {
-            textureSet = imageAtlasManager->Add(textureRect, encodedImageBuffer, desiredSize, fittingMode, true, atlasObserver);
-          }
-        }
-        else
+        const EncodedImageBuffer& encodedImageBuffer = GetEncodedImageBuffer(url.GetUrl());
+        if(encodedImageBuffer)
         {
-          textureSet = imageAtlasManager->Add(textureRect, url, atlasDesiredSize, fittingMode, true, atlasObserver);
+          textureSet = imageAtlasManager->Add(textureRect, encodedImageBuffer, desiredSize, fittingMode, true, atlasObserver);
         }
       }
-      if(!textureSet) // big image, no atlasing or atlasing failed
+      else
       {
-        atlasingStatus = false;
+        textureSet = imageAtlasManager->Add(textureRect, url, atlasDesiredSize, fittingMode, true, atlasObserver);
+      }
+    }
+    if(!textureSet) // big image, no atlasing or atlasing failed
+    {
+      atlasingStatus = false;
 
-        TextureId alphaMaskId        = INVALID_TEXTURE_ID;
-        float     contentScaleFactor = 1.0f;
-        bool      cropToMask         = false;
-        if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
-        {
-          maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, maskInfo->mPreappliedMasking ? TextureManager::StorageType::KEEP_PIXEL_BUFFER : TextureManager::StorageType::KEEP_TEXTURE, synchronousLoading);
-          alphaMaskId            = maskInfo->mAlphaMaskId;
-          if(maskInfo && maskInfo->mPreappliedMasking)
-          {
-            contentScaleFactor = maskInfo->mContentScaleFactor;
-            cropToMask         = maskInfo->mCropToMask;
-          }
-        }
+      TextureId alphaMaskId        = INVALID_TEXTURE_ID;
+      float     contentScaleFactor = 1.0f;
+      bool      cropToMask         = false;
+      if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
+      {
+        const bool preappliedMasking = maskInfo->mPreappliedMasking && (VisualUrl::TEXTURE != url.GetProtocolType());
+        maskInfo->mPreappliedMasking = preappliedMasking;
 
-        textureId = RequestLoad(
-          url,
-          alphaMaskId,
-          textureId,
-          contentScaleFactor,
-          desiredSize,
-          fittingMode,
-          samplingMode,
-          cropToMask,
-          textureObserver,
-          orientationCorrection,
-          reloadPolicy,
-          preMultiplyOnLoad,
-          synchronousLoading);
-
-        TextureManager::LoadState loadState = mTextureCacheManager.GetTextureStateInternal(textureId);
-        if(loadState == TextureManager::LoadState::UPLOADED)
+        maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, preappliedMasking ? TextureManager::StorageType::KEEP_PIXEL_BUFFER : TextureManager::StorageType::KEEP_TEXTURE, synchronousLoading);
+        alphaMaskId            = maskInfo->mAlphaMaskId;
+        if(maskInfo && preappliedMasking)
         {
-          // LoadComplete has already been called - keep the same texture set
-          textureSet = GetTextureSet(textureId);
+          contentScaleFactor = maskInfo->mContentScaleFactor;
+          cropToMask         = maskInfo->mCropToMask;
         }
-
-        // If we are loading the texture, or waiting for the ready signal handler to complete, inform
-        // caller that they need to wait.
-        loadingStatus = (loadState == TextureManager::LoadState::LOADING ||
-                         loadState == TextureManager::LoadState::WAITING_FOR_MASK ||
-                         loadState == TextureManager::LoadState::MASK_APPLYING ||
-                         loadState == TextureManager::LoadState::MASK_APPLIED ||
-                         loadState == TextureManager::LoadState::NOT_STARTED ||
-                         mLoadingQueueTextureId != INVALID_TEXTURE_ID);
       }
-      else
+
+      textureId = RequestLoad(
+        url,
+        alphaMaskId,
+        textureId,
+        contentScaleFactor,
+        desiredSize,
+        fittingMode,
+        samplingMode,
+        cropToMask,
+        textureObserver,
+        orientationCorrection,
+        reloadPolicy,
+        preMultiplyOnLoad,
+        synchronousLoading);
+
+      TextureManager::LoadState loadState = mTextureCacheManager.GetTextureState(textureId);
+      if(loadState == TextureManager::LoadState::UPLOADED)
       {
-        textureRectSize = atlasDesiredSize;
+        // LoadComplete has already been called - keep the same texture set
+        textureSet = GetTextureSet(textureId);
       }
+
+      // If we are loading the texture, or waiting for the ready signal handler to complete, inform
+      // caller that they need to wait.
+      loadingStatus = (loadState == TextureManager::LoadState::LOADING ||
+                       loadState == TextureManager::LoadState::WAITING_FOR_MASK ||
+                       loadState == TextureManager::LoadState::MASK_APPLYING ||
+                       loadState == TextureManager::LoadState::MASK_APPLIED ||
+                       loadState == TextureManager::LoadState::NOT_STARTED ||
+                       mLoadingQueueTextureId != INVALID_TEXTURE_ID);
+    }
+    else
+    {
+      textureRectSize = atlasDesiredSize;
     }
   }
 
@@ -498,6 +493,7 @@ TextureManager::TextureId TextureManager::RequestMaskLoad(
   const bool                        synchronousLoading)
 {
   // Use the normal load procedure to get the alpha mask.
+  // TODO : Is their any case to pre multiply required case?
   auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
   return RequestLoadInternal(maskUrl, INVALID_TEXTURE_ID, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), Dali::FittingMode::SCALE_TO_FILL, Dali::SamplingMode::NO_FILTER, false, storageType, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u, synchronousLoading);
 }
@@ -536,7 +532,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
   // Check if the requested Texture exists in the cache.
   if(cacheIndex != INVALID_CACHE_INDEX)
   {
-    if(TextureManager::ReloadPolicy::CACHED == reloadPolicy || TextureManager::INVALID_TEXTURE_ID == previousTextureId)
+    if(TextureManager::ReloadPolicy::CACHED == reloadPolicy || INVALID_TEXTURE_ID == previousTextureId)
     {
       // Mark this texture being used by another client resource, or Reload forced without request load before.
       // Forced reload which have current texture before, would replace the current texture.
@@ -546,8 +542,14 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
     textureId = mTextureCacheManager[cacheIndex].textureId;
 
     // Update preMultiplyOnLoad value. It should be changed according to preMultiplied value of the cached info.
-    preMultiplyOnLoad = mTextureCacheManager[cacheIndex].preMultiplied ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
-    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s size=%hux%hu observer=%p ) Using cached texture id@%d, textureId=%d, maskTextureId=%d, prevTextureId=%d, frameindex=%d, premultiplied=%d, refCount=%d\n", url.GetUrl().c_str(), desiredSize.GetWidth(), desiredSize.GetHeight(), observer, cacheIndex.GetIndex(), textureId, maskTextureId, previousTextureId, frameIndex, mTextureCacheManager[cacheIndex].preMultiplied ? 1 : 0, static_cast<int>(mTextureCacheManager[cacheIndex].referenceCount));
+    if(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD)
+    {
+      // Change preMultiplyOnLoad value so make caller determine to preMultiplyAlpha or not.
+      // TODO : Should we seperate input and output value?
+      preMultiplyOnLoad = mTextureCacheManager[cacheIndex].preMultiplied ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+    }
+
+    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s size=%hux%hu observer=%p ) Using cached texture id@%d, textureId=%d, maskTextureId=%d, prevTextureId=%d, frameindex=%d, orientCorrect=%d, premultiplied=%d, refCount=%d\n", url.GetUrl().c_str(), desiredSize.GetWidth(), desiredSize.GetHeight(), observer, cacheIndex.GetIndex(), textureId, maskTextureId, previousTextureId, frameIndex, orientationCorrection, mTextureCacheManager[cacheIndex].preMultiplied ? 1 : 0, static_cast<int>(mTextureCacheManager[cacheIndex].referenceCount));
   }
 
   if(textureId == INVALID_TEXTURE_ID) // There was no caching, or caching not required
@@ -558,7 +560,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
 
     // Cache new texutre, and get cacheIndex.
     cacheIndex = mTextureCacheManager.AppendCache(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex, loadYuvPlanes));
-    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s size=%hux%hu observer=%p ) New texture, cacheIndex:%d, textureId=%d, maskTextureId=%d, frameindex=%d premultiply=%d\n", url.GetUrl().c_str(), desiredSize.GetWidth(), desiredSize.GetHeight(), observer, cacheIndex.GetIndex(), textureId, maskTextureId, frameIndex, preMultiply);
+    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s size=%hux%hu observer=%p ) New texture, cacheIndex:%d, textureId=%d, maskTextureId=%d, frameindex=%d orientCorrect=%d premultiply=%d\n", url.GetUrl().c_str(), desiredSize.GetWidth(), desiredSize.GetHeight(), observer, cacheIndex.GetIndex(), textureId, maskTextureId, frameIndex, orientationCorrection, preMultiply);
   }
 
   // The below code path is common whether we are using the cache or not.
@@ -569,17 +571,13 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
   textureInfo.storageType           = storageType;
   textureInfo.orientationCorrection = orientationCorrection;
 
-  // the case using external texture has already been loaded texture, so change its status to WAITING_FOR_MASK.
+  // the case using external texture has already been loaded texture, so change its status to UPLOADED or WAITING_FOR_MASK.
   if(url.GetProtocolType() == VisualUrl::TEXTURE)
   {
-    if(textureInfo.loadState != TextureManager::LoadState::UPLOADED)
-    {
-      textureInfo.preMultiplied = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
-      textureInfo.loadState     = TextureManager::LoadState::WAITING_FOR_MASK;
-    }
+    UpdateExternalTextureInfo(textureInfo, preMultiplyOnLoad);
   }
 
-  DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureInfo loadState:%s\n", GET_LOAD_STATE_STRING(textureInfo.loadState));
+  DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureInfo loadState:%s, storageType:%s preMultiplyOnLoad:%d\n", GET_LOAD_STATE_STRING(textureInfo.loadState), GET_STORAGE_TYPE_STRING(textureInfo.storageType), (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD));
 
   // Force reloading of texture by setting loadState unless already loading or cancelled.
   if(TextureManager::ReloadPolicy::FORCED == reloadPolicy &&
@@ -588,7 +586,8 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
      TextureManager::LoadState::MASK_APPLYING != textureInfo.loadState &&
      TextureManager::LoadState::MASK_APPLIED != textureInfo.loadState &&
      TextureManager::LoadState::CANCELLED != textureInfo.loadState &&
-     TextureManager::LoadState::MASK_CANCELLED != textureInfo.loadState)
+     TextureManager::LoadState::MASK_CANCELLED != textureInfo.loadState &&
+     url.GetProtocolType() != VisualUrl::TEXTURE)
   {
     DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "TextureManager::RequestLoad( url=%s size=%hux%hu observer=%p ) ForcedReload cacheIndex:%d, textureId=%d, maskTextureId=%d, prevTextureId=%d\n", url.GetUrl().c_str(), desiredSize.GetWidth(), desiredSize.GetHeight(), observer, cacheIndex.GetIndex(), textureId, maskTextureId, previousTextureId);
     textureInfo.loadState = TextureManager::LoadState::NOT_STARTED;
@@ -612,7 +611,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
       case TextureManager::LoadState::MASK_APPLIED:
       {
         // Do not observe even we reload forced when texture is already loading state.
-        if(TextureManager::ReloadPolicy::CACHED == reloadPolicy || TextureManager::INVALID_TEXTURE_ID == previousTextureId)
+        if(TextureManager::ReloadPolicy::CACHED == reloadPolicy || INVALID_TEXTURE_ID == previousTextureId)
         {
           ObserveTexture(textureInfo, observer);
         }
@@ -662,15 +661,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
     {
       if(url.GetProtocolType() == VisualUrl::TEXTURE)
       {
-        // Get external textureSet from cacheManager.
-        std::string location = textureInfo.url.GetLocation();
-        if(!location.empty())
-        {
-          TextureId id                  = std::stoi(location);
-          auto      externalTextureInfo = mTextureCacheManager.GetExternalTextureInfo(id);
-          textureInfo.textures.push_back(externalTextureInfo.textureSet.GetTexture(0));
-          textureInfo.loadState = TextureManager::LoadState::UPLOADED;
-        }
+        UpdateExternalTextureInfo(textureInfo, preMultiplyOnLoad);
       }
       else
       {
@@ -691,7 +682,6 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
         }
         else // For the image loading.
         {
-          Texture maskTexture;
           if(maskTextureId != INVALID_TEXTURE_ID)
           {
             TextureCacheIndex maskCacheIndex = mTextureCacheManager.GetCacheIndexFromId(maskTextureId);
@@ -956,6 +946,7 @@ void TextureManager::ProcessLoadQueue()
       DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::ProcessLoadQueue() textureId=%d, observer=%p, cacheIndex=@%d, loadState:%s\n", element.mTextureId, element.mObserver, cacheIndex.GetIndex(), GET_LOAD_STATE_STRING(textureInfo.loadState));
 
       if((textureInfo.loadState == TextureManager::LoadState::UPLOADED) ||
+         (textureInfo.loadState == TextureManager::LoadState::LOAD_FAILED) ||
          (textureInfo.loadState == TextureManager::LoadState::LOAD_FINISHED &&
           textureInfo.storageType == TextureManager::StorageType::RETURN_PIXEL_BUFFER))
       {
@@ -964,7 +955,7 @@ void TextureManager::ProcessLoadQueue()
           DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "  Disconnect DestructionSignal to observer:%p\n", element.mObserver);
           element.mObserver->DestructionSignal().Disconnect(this, &TextureManager::ObserverDestroyed);
 
-          EmitLoadComplete(element.mObserver, textureInfo, true);
+          EmitLoadComplete(element.mObserver, textureInfo, (textureInfo.loadState != TextureManager::LoadState::LOAD_FAILED));
         }
       }
       else if(textureInfo.loadState == TextureManager::LoadState::LOADING)
@@ -1047,8 +1038,9 @@ void TextureManager::PostLoad(TextureManager::TextureInfo& textureInfo, std::vec
             }
             else
             {
-              LoadState maskLoadState = mTextureCacheManager.GetTextureStateInternal(textureInfo.maskTextureId);
+              LoadState maskLoadState = mTextureCacheManager.GetTextureState(textureInfo.maskTextureId);
               textureInfo.pixelBuffer = pixelBuffer; // Store the pixel buffer temporarily
+
               if(maskLoadState == TextureManager::LoadState::LOADING)
               {
                 textureInfo.loadState = TextureManager::LoadState::WAITING_FOR_MASK;
@@ -1161,53 +1153,56 @@ void TextureManager::CheckForWaitingTexture(TextureManager::TextureInfo& maskTex
 
       if(maskTextureInfo.loadState == TextureManager::LoadState::LOAD_FINISHED)
       {
-        if(maskTextureInfo.storageType == TextureManager::StorageType::KEEP_PIXEL_BUFFER)
-        {
-          ApplyMask(textureInfo, maskTextureInfo.textureId);
-        }
+        DALI_ASSERT_ALWAYS(maskTextureInfo.storageType == TextureManager::StorageType::KEEP_PIXEL_BUFFER && "Only KEEP_PIXEL_BUFFER storage type could be LOAD_FINISHED!");
+        ApplyMask(textureInfo, maskTextureInfo.textureId);
       }
       else if(maskTextureInfo.loadState == TextureManager::LoadState::UPLOADED)
       {
-        if(maskTextureInfo.storageType == TextureManager::StorageType::KEEP_TEXTURE)
+        DALI_ASSERT_ALWAYS(maskTextureInfo.storageType == TextureManager::StorageType::KEEP_TEXTURE && "Only KEEP_TEXTURE storage type could be UPLOADED!");
+        if(textureInfo.url.GetProtocolType() == VisualUrl::TEXTURE)
         {
-          if(textureInfo.url.GetProtocolType() == VisualUrl::TEXTURE)
-          {
-            // Get external textureSet from cacheManager.
-            std::string location = textureInfo.url.GetLocation();
-            if(!location.empty())
-            {
-              TextureId id                  = std::stoi(location);
-              auto      externalTextureInfo = mTextureCacheManager.GetExternalTextureInfo(id);
-              textureInfo.textures.push_back(externalTextureInfo.textureSet.GetTexture(0));
-              textureInfo.loadState = TextureManager::LoadState::UPLOADED;
-            }
-          }
-          else
+          // Just change load state WAITING_FOR_MASK to UPLOADED (Since we already upload texture)
+          if(textureInfo.loadState == TextureManager::LoadState::WAITING_FOR_MASK)
           {
-            // Upload image texture. textureInfo.loadState will be UPLOADED.
-            std::vector<Devel::PixelBuffer> pixelBuffers;
-            pixelBuffers.push_back(textureInfo.pixelBuffer);
-            UploadTextures(pixelBuffers, textureInfo);
+            textureInfo.loadState = TextureManager::LoadState::UPLOADED;
           }
+        }
+        else
+        {
+          // Upload image texture. textureInfo.loadState will be UPLOADED.
+          std::vector<Devel::PixelBuffer> pixelBuffers;
+          pixelBuffers.push_back(textureInfo.pixelBuffer);
+          UploadTextures(pixelBuffers, textureInfo);
+        }
 
-          // Increase reference counts for notify required textureId.
-          // Now we can assume that we don't remove & re-assign this textureId
-          // during NotifyObserver signal emit.
-          maskTextureInfo.referenceCount++;
-          textureInfo.referenceCount++;
+        // Increase reference counts for notify required textureId.
+        // Now we can assume that we don't remove & re-assign this textureId
+        // during NotifyObserver signal emit.
+        maskTextureInfo.referenceCount++;
+        textureInfo.referenceCount++;
 
-          DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::CheckForWaitingTexture(): Ready to notify textureId=%d\n", textureInfo.textureId);
+        DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::CheckForWaitingTexture(): Ready to notify textureId=%d\n", textureInfo.textureId);
 
-          notifyRequiredTextureIds.push_back(textureInfo.textureId);
-        }
+        notifyRequiredTextureIds.push_back(textureInfo.textureId);
       }
       else // maskTextureInfo.loadState == TextureManager::LoadState::LOAD_FAILED
       {
         // Url texture load success, But alpha mask texture load failed. Run as normal image upload.
         DALI_LOG_ERROR("Alpha mask image loading failed! Image will not be masked\n");
-        std::vector<Devel::PixelBuffer> pixelBuffers;
-        pixelBuffers.push_back(textureInfo.pixelBuffer);
-        UploadTextures(pixelBuffers, textureInfo);
+        if(maskTextureInfo.storageType == TextureManager::StorageType::KEEP_TEXTURE && textureInfo.url.GetProtocolType() == VisualUrl::TEXTURE)
+        {
+          // Just change load state WAITING_FOR_MASK to UPLOADED (Since we already upload texture)
+          if(textureInfo.loadState == TextureManager::LoadState::WAITING_FOR_MASK)
+          {
+            textureInfo.loadState = TextureManager::LoadState::UPLOADED;
+          }
+        }
+        else
+        {
+          std::vector<Devel::PixelBuffer> pixelBuffers;
+          pixelBuffers.push_back(textureInfo.pixelBuffer);
+          UploadTextures(pixelBuffers, textureInfo);
+        }
 
         // Increase reference counts for notify required textureId.
         // Now we can assume that we don't remove & re-assign this textureId
@@ -1327,7 +1322,7 @@ void TextureManager::NotifyObservers(TextureManager::TextureInfo& textureInfo, c
     // invalidating the reference to the textureInfo struct.
     // Texture load requests for the same URL are deferred until the end of this
     // method.
-    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::NotifyObservers() observer:%p textureId:%d size:%hux%hu url:%s loadState:%s\n", observer, textureId, info->desiredSize.GetWidth(), info->desiredSize.GetHeight(), info->url.GetUrl().c_str(), GET_LOAD_STATE_STRING(info->loadState));
+    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::NotifyObservers() observer:%p textureId:%d size:%hux%hu url:%s loadState:%s premultiplied:%d\n", observer, textureId, info->desiredSize.GetWidth(), info->desiredSize.GetHeight(), info->url.GetUrl().c_str(), GET_LOAD_STATE_STRING(info->loadState), info->preMultiplied);
     // It is possible for the observer to be deleted.
     // Disconnect and remove the observer first.
     DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "  Disconnect DestructionSignal to observer:%p\n", observer);
@@ -1402,7 +1397,7 @@ void TextureManager::EmitLoadComplete(TextureUploadObserver* observer, TextureMa
   }
   else
   {
-    TextureSet textureSet = GetTextureSet(textureInfo);
+    TextureSet textureSet = GetTextureSetInternal(textureInfo);
     if(textureInfo.isAnimatedImageFormat)
     {
       observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::ANIMATED_IMAGE_TEXTURE, textureInfo.textureId, textureSet, textureInfo.frameCount, textureInfo.frameInterval, textureInfo.preMultiplied));
@@ -1417,24 +1412,58 @@ void TextureManager::EmitLoadComplete(TextureUploadObserver* observer, TextureMa
 TextureSet TextureManager::GetTextureSet(const TextureManager::TextureId textureId)
 {
   TextureSet                textureSet;
-  TextureManager::LoadState loadState = mTextureCacheManager.GetTextureStateInternal(textureId);
+  TextureManager::LoadState loadState = mTextureCacheManager.GetTextureState(textureId);
   if(loadState == TextureManager::LoadState::UPLOADED)
   {
     TextureCacheIndex textureCacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureId);
     if(textureCacheIndex != INVALID_CACHE_INDEX)
     {
       TextureInfo& textureInfo(mTextureCacheManager[textureCacheIndex]);
-      textureSet = GetTextureSet(textureInfo);
+      textureSet = GetTextureSetInternal(textureInfo);
     }
   }
-  else
+
+  if(!textureSet)
   {
-    DALI_LOG_ERROR("GetTextureSet is failed. texture is not uploaded \n");
+    DALI_LOG_ERROR("GetTextureSet(%d) is failed. texture is not uploaded \n", textureId);
   }
   return textureSet;
 }
 
-TextureSet TextureManager::GetTextureSet(const TextureManager::TextureInfo& textureInfo)
+void TextureManager::RemoveTextureObserver(TextureManager::TextureInfo& textureInfo, TextureUploadObserver* observer)
+{
+  if(observer)
+  {
+    const auto iterEnd = textureInfo.observerList.End();
+    const auto iter    = std::find(textureInfo.observerList.Begin(), iterEnd, observer);
+    if(iter != iterEnd)
+    {
+      // Disconnect and remove the observer.
+      DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "  Disconnect DestructionSignal to observer:%p\n", observer);
+      observer->DestructionSignal().Disconnect(this, &TextureManager::ObserverDestroyed);
+      textureInfo.observerList.Erase(iter);
+    }
+    else
+    {
+      // Given textureId might exist at load queue.
+      // Remove observer from the LoadQueue
+      for(auto&& element : mLoadQueue)
+      {
+        if(element.mTextureId == textureInfo.textureId && element.mObserver == observer)
+        {
+          DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "Remove observer from observer queue (textureId:%d, observer:%p)\n", element.mTextureId, element.mObserver);
+          DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "  Disconnect DestructionSignal to observer:%p\n", observer);
+          observer->DestructionSignal().Disconnect(this, &TextureManager::ObserverDestroyed);
+          element.mObserver = nullptr;
+          break;
+        }
+      }
+    }
+  }
+}
+
+// Internal methods
+TextureSet TextureManager::GetTextureSetInternal(const TextureManager::TextureInfo& textureInfo)
 {
   TextureSet textureSet;
 
@@ -1451,18 +1480,22 @@ TextureSet TextureManager::GetTextureSet(const TextureManager::TextureInfo& text
         textureSet.SetTexture(index++, texture);
       }
     }
-    else
+    else if(textureInfo.textures.size() > TEXTURE_INDEX)
     {
-      textureSet.SetTexture(TEXTURE_INDEX, textureInfo.textures[0]);
-      TextureCacheIndex maskCacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureInfo.maskTextureId);
-      if(maskCacheIndex != INVALID_CACHE_INDEX)
+      textureSet.SetTexture(TEXTURE_INDEX, textureInfo.textures[TEXTURE_INDEX]);
+      if(textureInfo.maskTextureId != INVALID_TEXTURE_ID)
       {
-        TextureInfo& maskTextureInfo(mTextureCacheManager[maskCacheIndex]);
-        if(maskTextureInfo.storageType == TextureManager::StorageType::UPLOAD_TO_TEXTURE || maskTextureInfo.storageType == TextureManager::StorageType::KEEP_TEXTURE)
+        TextureCacheIndex maskCacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureInfo.maskTextureId);
+        if(maskCacheIndex != INVALID_CACHE_INDEX)
         {
-          if(!maskTextureInfo.textures.empty())
+          TextureInfo& maskTextureInfo(mTextureCacheManager[maskCacheIndex]);
+          if(maskTextureInfo.storageType == TextureManager::StorageType::UPLOAD_TO_TEXTURE ||
+             maskTextureInfo.storageType == TextureManager::StorageType::KEEP_TEXTURE)
           {
-            textureSet.SetTexture(MASK_TEXTURE_INDEX, maskTextureInfo.textures[0]);
+            if(maskTextureInfo.textures.size() > TEXTURE_INDEX)
+            {
+              textureSet.SetTexture(MASK_TEXTURE_INDEX, maskTextureInfo.textures[TEXTURE_INDEX]);
+            }
           }
         }
       }
@@ -1471,36 +1504,64 @@ TextureSet TextureManager::GetTextureSet(const TextureManager::TextureInfo& text
   return textureSet;
 }
 
-void TextureManager::RemoveTextureObserver(TextureManager::TextureInfo& textureInfo, TextureUploadObserver* observer)
+void TextureManager::UpdateExternalTextureInfo(TextureManager::TextureInfo& textureInfo, TextureManager::MultiplyOnLoad& preMultiplyOnLoad)
 {
-  if(observer)
+  DALI_ASSERT_DEBUG(textureInfo.url.GetProtocolType() == VisualUrl::TEXTURE);
+
+  if(textureInfo.loadState == TextureManager::LoadState::UPLOADED ||
+     textureInfo.loadState == TextureManager::LoadState::WAITING_FOR_MASK ||
+     textureInfo.loadState == TextureManager::LoadState::LOAD_FAILED)
   {
-    const auto iterEnd = textureInfo.observerList.End();
-    const auto iter    = std::find(textureInfo.observerList.Begin(), iterEnd, observer);
-    if(iter != iterEnd)
-    {
-      // Disconnect and remove the observer.
-      DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "  Disconnect DestructionSignal to observer:%p\n", observer);
-      observer->DestructionSignal().Disconnect(this, &TextureManager::ObserverDestroyed);
-      textureInfo.observerList.Erase(iter);
-    }
-    else
+    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::GetInfo already called before. (textureId=%d url:%s premultiplied=%d, loadState:%s)\n", textureInfo.textureId, textureInfo.url.GetUrl().c_str(), textureInfo.preMultiplied, GET_LOAD_STATE_STRING(textureInfo.loadState));
+    return;
+  }
+
+  // To reduce duplicated failed case branch out, set loadState to LOAD_FAILED first.
+  textureInfo.loadState = TextureManager::LoadState::LOAD_FAILED;
+
+  // Get Texture from external textureset
+  TextureId externalTextureId = INVALID_TEXTURE_ID;
+  if(textureInfo.url.GetLocationAsInteger(externalTextureId) && externalTextureId != INVALID_TEXTURE_ID)
+  {
+    const auto& externalTextureInfo = mTextureCacheManager.GetExternalTextureInfo(externalTextureId);
+
+    if(externalTextureInfo.textureSet && externalTextureInfo.textureSet.GetTextureCount() > TEXTURE_INDEX)
     {
-      // Given textureId might exist at load queue.
-      // Remove observer from the LoadQueue
-      for(auto&& element : mLoadQueue)
+      auto externalTexture = externalTextureInfo.textureSet.GetTexture(TEXTURE_INDEX);
+      if(externalTexture)
       {
-        if(element.mTextureId == textureInfo.textureId && element.mObserver == observer)
+        textureInfo.textures.push_back(externalTexture);
+
+        if(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD)
         {
-          DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "Remove observer from observer queue (textureId:%d, observer:%p)\n", element.mTextureId, element.mObserver);
-          DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "  Disconnect DestructionSignal to observer:%p\n", observer);
-          observer->DestructionSignal().Disconnect(this, &TextureManager::ObserverDestroyed);
-          element.mObserver = nullptr;
-          break;
+          // TODO : Shouldn't we check preMultiplied value of external texture when TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY??
+          textureInfo.preMultiplied = externalTextureInfo.preMultiplied;
+
+          // Change preMultiplyOnLoad value so make caller determine to preMultiplyAlpha or not.
+          // TODO : Should we seperate input and output value?
+          preMultiplyOnLoad = textureInfo.preMultiplied ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+        }
+
+        if(textureInfo.maskTextureId != INVALID_TEXTURE_ID)
+        {
+          textureInfo.loadState = TextureManager::LoadState::WAITING_FOR_MASK;
+
+          // Check if mask texutre is already uploaded or not.
+          TextureManager::LoadState maskLoadState = mTextureCacheManager.GetTextureState(textureInfo.maskTextureId);
+          if(maskLoadState == TextureManager::LoadState::UPLOADED ||
+             maskLoadState == TextureManager::LoadState::LOAD_FAILED)
+          {
+            textureInfo.loadState = TextureManager::LoadState::UPLOADED;
+          }
+        }
+        else
+        {
+          textureInfo.loadState = TextureManager::LoadState::UPLOADED;
         }
       }
     }
   }
+  DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::GetInfo from external. (textureId=%d url:%s exernalTextureId=%d premultiplied=%d, loadState:%s)\n", textureInfo.textureId, textureInfo.url.GetUrl().c_str(), externalTextureId, textureInfo.preMultiplied, GET_LOAD_STATE_STRING(textureInfo.loadState));
 }
 
 } // namespace Internal
index 979839ceb941f7c57ec8ff6f86cda7a0d0eaf86f..fe5062108d357b6ee7f97d0244bafc8312faf2cb 100644 (file)
@@ -232,13 +232,6 @@ public:
    */
   TextureSet GetTextureSet(const TextureManager::TextureId textureId);
 
-  /**
-   * @brief Returns the textureSet in texture manager.
-   * @param[in] textureInfo the information of the texture
-   * @return The textureSet in texture manager. These textures include YUV textures or images and masks.
-   */
-  TextureSet GetTextureSet(const TextureManager::TextureInfo& textureInfo);
-
 public:
   // API list that need to access TextureCacheManager.
 
@@ -623,6 +616,21 @@ private:
    */
   void RemoveTextureObserver(TextureManager::TextureInfo& textureInfo, TextureUploadObserver* observer);
 
+private: // Internal methods
+  /**
+   * @brief Returns the textureSet in texture manager.
+   * @param[in] textureInfo the information of the texture
+   * @return The textureSet in texture manager. These textures include YUV textures or images and masks.
+   */
+  TextureSet GetTextureSetInternal(const TextureManager::TextureInfo& textureInfo);
+
+  /**
+   * @brief Update texture info from external texture info if url is external texture.
+   * @param[in,out] textureInfo the information of the texture
+   * @param[in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the image has no alpha channel
+   */
+  void UpdateExternalTextureInfo(TextureManager::TextureInfo& textureInfo, TextureManager::MultiplyOnLoad& preMultiplyOnLoad);
+
 public:
   /**
    * @brief Common method to handle loading completion.
index a61a9bdbebb7bbdcd81203106161eb388b93d03b..1756cce6f9e3b21b5a7f5bb7b5c504a94a86de22 100644 (file)
@@ -21,6 +21,7 @@
 // EXTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/image-loading.h>
 #include <dali/devel-api/adaptor-framework/window-devel.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/rendering/decorated-visual-renderer.h>
 #include <memory>
@@ -184,7 +185,14 @@ AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache
     ImageCache::UrlStore urlStore;
     urlStore.mTextureId = TextureManager::INVALID_TEXTURE_ID;
     urlStore.mUrl       = imageUrls[i].Get<std::string>();
-    visual->mImageUrls->push_back(urlStore);
+    if(DALI_LIKELY(Dali::Adaptor::IsAvailable()))
+    {
+      // Increase reference count of External Resources :
+      // EncodedImageBuffer or ExternalTextures.
+      // Reference count will be decreased at destructor of the visual.
+      urlStore.mUrl.IncreaseExternalResourceReference(factoryCache.GetTextureManager());
+    }
+    visual->mImageUrls->push_back(std::move(urlStore));
   }
   visual->mFrameCount = imageUrls.Count();
   visual->SetProperties(properties);
@@ -220,7 +228,14 @@ void AnimatedImageVisual::InitializeAnimatedImage(const VisualUrl& imageUrl)
       ImageCache::UrlStore urlStore;
       urlStore.mTextureId = TextureManager::INVALID_TEXTURE_ID;
       urlStore.mUrl       = imageUrl;
-      mImageUrls->push_back(urlStore);
+      if(DALI_LIKELY(Dali::Adaptor::IsAvailable()))
+      {
+        // Increase reference count of External Resources :
+        // EncodedImageBuffer or ExternalTextures.
+        // Reference count will be decreased at destructor of the visual.
+        urlStore.mUrl.IncreaseExternalResourceReference(mFactoryCache.GetTextureManager());
+      }
+      mImageUrls->push_back(std::move(urlStore));
     }
     mFrameCount = SINGLE_IMAGE_COUNT;
   }
@@ -243,6 +258,7 @@ void AnimatedImageVisual::CreateImageCache()
     uint16_t numUrls   = mImageUrls->size();
     uint16_t batchSize = std::max(std::min(mBatchSize, numUrls), MINIMUM_CACHESIZE);
     uint16_t cacheSize = std::max(std::min(std::max(batchSize, mCacheSize), numUrls), MINIMUM_CACHESIZE);
+
     if(cacheSize < numUrls)
     {
       mImageCache = new RollingImageCache(textureManager, mDesiredSize, mFittingMode, mSamplingMode, *mImageUrls, mMaskingData, *this, cacheSize, batchSize, mFrameDelay, IsPreMultipliedAlphaEnabled());
@@ -271,8 +287,8 @@ AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, Image
   mAnimatedImageLoading(),
   mFrameIndexForJumpTo(0),
   mCurrentFrameIndex(FIRST_FRAME_INDEX),
-  mImageUrls(NULL),
-  mImageCache(NULL),
+  mImageUrls(nullptr),
+  mImageCache(nullptr),
   mCacheSize(2),
   mBatchSize(2),
   mFrameDelay(100),
@@ -308,6 +324,24 @@ AnimatedImageVisual::~AnimatedImageVisual()
       mImageCache->ClearCache();
     }
   }
+
+  if(DALI_LIKELY(Dali::Adaptor::IsAvailable()))
+  {
+    TextureManager& textureManager = mFactoryCache.GetTextureManager();
+
+    if(mImageUrls != nullptr && !mImageUrls->empty())
+    {
+      for(const auto& urlStore : *mImageUrls)
+      {
+        urlStore.mUrl.DecreaseExternalResourceReference(textureManager);
+      }
+    }
+
+    if(mMaskingData)
+    {
+      mMaskingData->mAlphaMaskUrl.DecreaseExternalResourceReference(textureManager);
+    }
+  }
   delete mImageCache;
   delete mImageUrls;
 }
@@ -384,7 +418,7 @@ void AnimatedImageVisual::DoCreatePropertyMap(Property::Map& map) const
   {
     map.Insert(Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl());
   }
-  if(mImageUrls != NULL && !mImageUrls->empty())
+  if(mImageUrls != nullptr && !mImageUrls->empty())
   {
     Property::Array urls;
     for(unsigned int i = 0; i < mImageUrls->size(); ++i)
@@ -783,6 +817,20 @@ void AnimatedImageVisual::DoSetProperty(Property::Index        index,
       {
         AllocateMaskData();
         mMaskingData->mAlphaMaskUrl = alphaUrl;
+        if(mMaskingData->mAlphaMaskUrl.IsValid())
+        {
+          if(DALI_LIKELY(Dali::Adaptor::IsAvailable()))
+          {
+            // Increase reference count of External Resources :
+            // EncodedImageBuffer or ExternalTextures.
+            // Reference count will be decreased at destructor of the visual.
+            mMaskingData->mAlphaMaskUrl.IncreaseExternalResourceReference(mFactoryCache.GetTextureManager());
+          }
+          if(mMaskingData->mAlphaMaskUrl.GetProtocolType() == VisualUrl::TEXTURE)
+          {
+            mMaskingData->mPreappliedMasking = false;
+          }
+        }
       }
       break;
     }
@@ -815,7 +863,35 @@ void AnimatedImageVisual::DoSetProperty(Property::Index        index,
       if(value.Get(maskingType))
       {
         AllocateMaskData();
-        mMaskingData->mPreappliedMasking = Toolkit::DevelImageVisual::MaskingType::Type(maskingType) == Toolkit::DevelImageVisual::MaskingType::MASKING_ON_LOADING ? true : false;
+
+        bool externalTextureUsed = false;
+        if(mMaskingData->mAlphaMaskUrl.IsValid() && mMaskingData->mAlphaMaskUrl.GetProtocolType() == VisualUrl::TEXTURE)
+        {
+          externalTextureUsed = true;
+        }
+        else if(mImageUrls != nullptr && !mImageUrls->empty())
+        {
+          for(const auto& urlStore : *mImageUrls)
+          {
+            const auto& imageUrl = urlStore.mUrl;
+            if(imageUrl.IsValid() && imageUrl.GetProtocolType() == VisualUrl::TEXTURE)
+            {
+              externalTextureUsed = true;
+              break;
+            }
+          }
+        }
+
+        if(externalTextureUsed)
+        {
+          // For external textures, only gpu masking is available.
+          // Therefore, MASKING_TYPE is set to MASKING_ON_RENDERING forcelly.
+          mMaskingData->mPreappliedMasking = false;
+        }
+        else
+        {
+          mMaskingData->mPreappliedMasking = (Toolkit::DevelImageVisual::MaskingType::Type(maskingType) == Toolkit::DevelImageVisual::MaskingType::MASKING_ON_LOADING);
+        }
       }
       break;
     }
@@ -1032,16 +1108,16 @@ void AnimatedImageVisual::OnInitialize()
     mPixelAreaIndex = mImpl->mRenderer.RegisterUniqueProperty(Toolkit::ImageVisual::Property::PIXEL_AREA, PIXEL_AREA_UNIFORM_NAME, mPixelArea);
   }
 
-  if(mMaskingData)
-  {
-    mImpl->mRenderer.RegisterUniqueProperty(Toolkit::ImageVisual::Property::CROP_TO_MASK, CROP_TO_MASK_NAME, static_cast<float>(mMaskingData->mCropToMask));
-  }
-
   // Enable PreMultipliedAlpha if it need.
   auto preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader
                              ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD
                              : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
   EnablePreMultipliedAlpha(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
+
+  if(mMaskingData)
+  {
+    mImpl->mRenderer.RegisterUniqueProperty(Toolkit::ImageVisual::Property::CROP_TO_MASK, CROP_TO_MASK_NAME, static_cast<float>(mMaskingData->mCropToMask));
+  }
 }
 
 void AnimatedImageVisual::StartFirstFrame(TextureSet& textureSet, uint32_t firstInterval)
@@ -1271,6 +1347,21 @@ void AnimatedImageVisual::AllocateMaskData()
   if(!mMaskingData)
   {
     mMaskingData.reset(new TextureManager::MaskingData());
+
+    // Note : If input url was TEXTURE protocol, it will fail to create AnimatedImageLoading.
+    // So it should be added at mImageUrls.
+    if(mImageUrls != nullptr && !mImageUrls->empty())
+    {
+      for(const auto& urlStore : *mImageUrls)
+      {
+        const auto& imageUrl = urlStore.mUrl;
+        if(imageUrl.IsValid() && imageUrl.GetProtocolType() == VisualUrl::TEXTURE)
+        {
+          mMaskingData->mPreappliedMasking = false;
+          break;
+        }
+      }
+    }
   }
 }
 
index e718db760b6e94e6b42a5dee099577170507e673..256661882e745a7dbd8ad36c9aa8325fb0c05e66 100644 (file)
@@ -222,20 +222,13 @@ ImageVisual::~ImageVisual()
 {
   if(DALI_LIKELY(Dali::Adaptor::IsAvailable()))
   {
-    if(mImageUrl.IsValid())
     {
-      // Decrease reference count of External Resources :
-      // EncodedImageBuffer or ExternalTextures.
-      // Ensure the stage is still valid before accessing texture manager.
-      if(mImageUrl.GetProtocolType() == VisualUrl::TEXTURE)
-      {
-        TextureManager& textureManager = mFactoryCache.GetTextureManager();
-        textureManager.RemoveExternalTexture(mImageUrl);
-      }
-      else if(mImageUrl.IsBufferResource())
+      TextureManager& textureManager = mFactoryCache.GetTextureManager();
+
+      mImageUrl.DecreaseExternalResourceReference(textureManager);
+      if(mMaskingData)
       {
-        TextureManager& textureManager = mFactoryCache.GetTextureManager();
-        textureManager.RemoveEncodedImageBuffer(mImageUrl);
+        mMaskingData->mAlphaMaskUrl.DecreaseExternalResourceReference(textureManager);
       }
     }
 
@@ -397,6 +390,20 @@ void ImageVisual::DoSetProperty(Property::Index index, const Property::Value& va
       {
         AllocateMaskData();
         mMaskingData->mAlphaMaskUrl = alphaUrl;
+        if(mMaskingData->mAlphaMaskUrl.IsValid())
+        {
+          if(DALI_LIKELY(Dali::Adaptor::IsAvailable()))
+          {
+            // Increase reference count of External Resources :
+            // EncodedImageBuffer or ExternalTextures.
+            // Reference count will be decreased at destructor of the visual.
+            mMaskingData->mAlphaMaskUrl.IncreaseExternalResourceReference(mFactoryCache.GetTextureManager());
+          }
+          if(mMaskingData->mAlphaMaskUrl.GetProtocolType() == VisualUrl::TEXTURE)
+          {
+            mMaskingData->mPreappliedMasking = false;
+          }
+        }
       }
       break;
     }
@@ -429,7 +436,18 @@ void ImageVisual::DoSetProperty(Property::Index index, const Property::Value& va
       if(value.Get(maskingType))
       {
         AllocateMaskData();
+
+        bool externalTextureUsed = false;
         if(mImageUrl.IsValid() && mImageUrl.GetProtocolType() == VisualUrl::TEXTURE)
+        {
+          externalTextureUsed = true;
+        }
+        else if(mMaskingData->mAlphaMaskUrl.IsValid() && mMaskingData->mAlphaMaskUrl.GetProtocolType() == VisualUrl::TEXTURE)
+        {
+          externalTextureUsed = true;
+        }
+
+        if(externalTextureUsed)
         {
           // For external textures, only gpu masking is available.
           // Therefore, MASKING_TYPE is set to MASKING_ON_RENDERING forcelly.
@@ -615,13 +633,12 @@ void ImageVisual::GetNaturalSize(Vector2& naturalSize)
 
 void ImageVisual::OnInitialize()
 {
-  // Increase reference count of External Resources :
-  // EncodedImageBuffer or ExternalTextures.
-  // Reference count will be decreased at destructor of the visual.
-  if(mImageUrl.IsValid() && (mImageUrl.IsBufferResource() || mImageUrl.GetProtocolType() == VisualUrl::TEXTURE))
+  if(DALI_LIKELY(Dali::Adaptor::IsAvailable()))
   {
-    TextureManager& textureManager = mFactoryCache.GetTextureManager();
-    textureManager.UseExternalResource(mImageUrl);
+    // Increase reference count of External Resources :
+    // EncodedImageBuffer or ExternalTextures.
+    // Reference count will be decreased at destructor of the visual.
+    mImageUrl.IncreaseExternalResourceReference(mFactoryCache.GetTextureManager());
   }
 
   // Generate geometry and shader. Note that we should check AddOn when generate geometry, due to LoadPolicy::IMMEDIATE case
index 803c5d65920481cdd5668e97c2488dc9e41a9f58..47b2b45b6c508b3118f0574c03817c5743abc722 100644 (file)
@@ -309,12 +309,13 @@ Toolkit::Visual::Base VisualFactory::CreateVisual(const Property::Map& propertyM
     }
   }
 
-  DALI_LOG_INFO(gLogFilter, Debug::Concise, "VisualFactory::CreateVisual( VisualType:%s %s%s)\n", Scripting::GetEnumerationName<Toolkit::DevelVisual::Type>(visualType, VISUAL_TYPE_TABLE, VISUAL_TYPE_TABLE_COUNT), (visualType == Toolkit::DevelVisual::IMAGE) ? "url:" : "", (visualType == Toolkit::DevelVisual::IMAGE) ? (([&]() {
-                  // Return URL if present in PropertyMap else return "not found message"
-                  Property::Value* imageURLValue = propertyMap.Find(Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME);
-                  return (imageURLValue) ? imageURLValue->Get<std::string>().c_str() : "url not found in PropertyMap";
-                })())
-                                                                                                                                                                                                                                                                                                                            : "");
+  DALI_LOG_INFO(gLogFilter, Debug::Concise, "VisualFactory::CreateVisual( VisualType:%s %s%s)\n", Scripting::GetEnumerationName<Toolkit::DevelVisual::Type>(visualType, VISUAL_TYPE_TABLE, VISUAL_TYPE_TABLE_COUNT), (visualType == Toolkit::DevelVisual::IMAGE) ? "url:" : "", ((visualType == Toolkit::DevelVisual::IMAGE) ? (([&]() {
+                                                                                                                                                                                                                                                                                  // Return URL if present in PropertyMap else return "not found message"
+                                                                                                                                                                                                                                                                                  Property::Value* imageURLValue = propertyMap.Find(Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME);
+                                                                                                                                                                                                                                                                                  return (imageURLValue) ? imageURLValue->Get<std::string>() : std::string("url not found in PropertyMap");
+                                                                                                                                                                                                                                                                                })())
+                                                                                                                                                                                                                                                                                                                             : std::string(""))
+                                                                                                                                                                                                                                                                                  .c_str());
 
   if(!visualPtr)
   {
index 2f16427ab990f45c7ba64a6f56e9492008d6bc2b..35d507c252ff46ecdec06c37eb351f6b938e6848 100644 (file)
@@ -21,6 +21,9 @@
 #include <dali/devel-api/common/hash.h>
 #include <cstring> // for toupper()
 
+// INTERNAL HEADERS
+#include <dali-toolkit/internal/texture-manager/texture-manager-impl.h>
+
 namespace Dali
 {
 namespace Toolkit
@@ -348,6 +351,52 @@ std::string VisualUrl::GetLocationWithoutExtension() const
   return GetLocationWithoutExtension(mUrl);
 }
 
+bool VisualUrl::GetLocationAsInteger(int32_t& integerLocation) const
+{
+  const auto& location = GetLocationWithoutExtension(mUrl);
+  if(!location.empty())
+  {
+    try
+    {
+      integerLocation = std::stoi(location);
+      return true;
+    }
+    catch(...)
+    {
+      return false;
+    }
+  }
+  return false;
+}
+
+void VisualUrl::IncreaseExternalResourceReference(TextureManager& textureManager) const
+{
+  if(IsValid() && (mLocation == VisualUrl::TEXTURE || mLocation == VisualUrl::BUFFER))
+  {
+    textureManager.UseExternalResource(*this);
+  }
+}
+
+void VisualUrl::DecreaseExternalResourceReference(TextureManager& textureManager) const
+{
+  if(IsValid() && (mLocation == VisualUrl::TEXTURE || mLocation == VisualUrl::BUFFER))
+  {
+    switch(mLocation)
+    {
+      case VisualUrl::TEXTURE:
+      {
+        textureManager.RemoveExternalTexture(*this);
+        break;
+      }
+      case VisualUrl::BUFFER:
+      {
+        textureManager.RemoveEncodedImageBuffer(*this);
+        break;
+      }
+    }
+  }
+}
+
 std::string VisualUrl::CreateTextureUrl(const std::string& location)
 {
   return "dali://" + location;
@@ -375,14 +424,13 @@ std::string VisualUrl::GetLocation(const std::string& url)
 
 std::string VisualUrl::GetLocationWithoutExtension(const std::string& url)
 {
-  const auto location = url.find("://");
-  if(std::string::npos != location)
-  {
-    const auto extension      = url.find_last_of("."); // Find last position of '.' keyword.
-    const auto locationLength = extension != std::string::npos ? extension - (location + 3u) : std::string::npos;
-    return url.substr(location + 3u, locationLength); // 3 characters forwards from the start of ://, and end of last '.' keyword.
-  }
-  return url;
+  const auto location  = url.find("://");
+  const auto extension = url.find_last_of("."); // Find last position of '.' keyword.
+
+  const auto locationOffset = location != std::string::npos ? location + 3u : 0u;
+  const auto locationLength = extension != std::string::npos ? extension - (locationOffset) : std::string::npos;
+
+  return url.substr(locationOffset, locationLength);
 }
 
 } // namespace Internal
index 8caf71691f8fc659c9b9790f6e95989194712860..41ccb27b4ea24b39d00abb5fcf25e4a18f112618 100644 (file)
@@ -28,6 +28,8 @@ namespace Toolkit
 {
 namespace Internal
 {
+class TextureManager;
+
 class VisualUrl
 {
 public:
@@ -154,6 +156,34 @@ public:
    */
   std::string GetLocationWithoutExtension() const;
 
+  /**
+   * @brief Convert the location part of the url as single integer
+   *
+   * @param[out] integerLocation The result of conversion.
+   * @return True if the location can be converted to integer. Otherwise false.
+   */
+  bool GetLocationAsInteger(int32_t& integerLocation) const;
+
+  /**
+   * @brief Increase the external resource reference count.
+   * Only have effort if ProtocolType is TEXTURE or BUFFER.
+   * 
+   * @post DecreaseExternalResourceReference Should be called when the resource is no longer needed.
+   *
+   * @param[in] textureManager The texture manager who owns the external texture.
+   */
+  void IncreaseExternalResourceReference(TextureManager& textureManager) const;
+
+  /**
+   * @brief Decrease the external resource reference count.
+   * Only have effort if ProtocolType is TEXTURE or BUFFER.
+   *
+   * @pre IncreaseExternalResourceReference Should be called before calling this function.
+   *
+   * @param[in] textureManager The texture manager who owns the external texture.
+   */
+  void DecreaseExternalResourceReference(TextureManager& textureManager) const;
+
   /**
    * Helper to create a URL of type TEXTURE
    * @param location the location of the texture