Merge "[AT-SPI] ScrollView: Use child postion for ScrollToChild" into devel/master
authorShinwoo Kim <cinoo.kim@samsung.com>
Tue, 3 May 2022 03:31:22 +0000 (03:31 +0000)
committerGerrit Code Review <gerrit@review>
Tue, 3 May 2022 03:31:22 +0000 (03:31 +0000)
37 files changed:
automated-tests/src/dali-scene-loader/utc-Dali-Gltf2Loader.cpp
automated-tests/src/dali-scene-loader/utc-Dali-ShaderDefinitionFactory.cpp
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/dali-toolkit-test-utils/toolkit-input-method-context.h
automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp
automated-tests/src/dali-toolkit/utc-Dali-KeyboardFocusManager.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp
dali-scene-loader/internal/gltf2-asset.h
dali-scene-loader/internal/graphics/shaders/default-physically-based-shader.frag [new file with mode: 0644]
dali-scene-loader/internal/graphics/shaders/default-physically-based-shader.vert [new file with mode: 0644]
dali-scene-loader/public-api/gltf2-loader.cpp
dali-scene-loader/public-api/material-definition.cpp
dali-scene-loader/public-api/material-definition.h
dali-scene-loader/public-api/node-definition.cpp
dali-scene-loader/public-api/shader-definition-factory.cpp
dali-scene-loader/public-api/shader-definition.cpp
dali-scene-loader/public-api/shader-definition.h
dali-toolkit/devel-api/controls/scene3d-view/scene3d-view.h
dali-toolkit/internal/controls/scene3d-view/gltf-loader.cpp
dali-toolkit/internal/controls/scene3d-view/scene3d-view-impl.cpp
dali-toolkit/internal/controls/scene3d-view/scene3d-view-impl.h
dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp
dali-toolkit/internal/graphics/shaders/gltf-physically-based-shader.frag
dali-toolkit/internal/graphics/shaders/gltf-physically-based-shader.vert
dali-toolkit/internal/image-loader/image-url-impl.cpp
dali-toolkit/internal/text/text-controller-event-handler.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/texture-manager/texture-manager-type.h
dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/visual-url.cpp
dali-toolkit/public-api/dali-toolkit-version.cpp
packaging/dali-toolkit.spec

index 47515b3..b4dceb9 100644 (file)
@@ -167,12 +167,15 @@ int UtcDaliGltfLoaderSuccess1(void)
   DALI_TEST_EQUAL(2u, materials.size());
   const MaterialDefinition materialGroundTruth[]{
     {MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
+       MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION |
        MaterialDefinition::NORMAL | MaterialDefinition::TRANSPARENCY | MaterialDefinition::GLTF_CHANNELS |
        (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
      0,
      Vector4(1.f, .766f, .336f, 1.f),
+     Vector3(0.2, 0.1, 0.0),
      1.f,
      0.f,
+     1.f,
      {
        {MaterialDefinition::ALBEDO,
         {"AnimatedCube_BaseColor.png",
@@ -183,13 +186,22 @@ int UtcDaliGltfLoaderSuccess1(void)
        {MaterialDefinition::NORMAL,
         {"AnimatedCube_BaseColor.png",
          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
+       {MaterialDefinition::OCCLUSION,
+        {"AnimatedCube_BaseColor.png",
+         SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
+       {MaterialDefinition::EMISSIVE,
+        {"AnimatedCube_BaseColor.png",
+         SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
      }},
     {MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
+       MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION |
        MaterialDefinition::NORMAL | MaterialDefinition::GLTF_CHANNELS,
      0,
      Vector4(1.f, .766f, .336f, 1.f),
+     Vector3(0.2, 0.1, 0.0),
      1.f,
      0.f,
+     1.f,
      {
        {MaterialDefinition::ALBEDO,
         {"AnimatedCube_BaseColor.png",
@@ -200,6 +212,12 @@ int UtcDaliGltfLoaderSuccess1(void)
        {MaterialDefinition::NORMAL,
         {"AnimatedCube_BaseColor.png",
          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
+       {MaterialDefinition::OCCLUSION,
+        {"AnimatedCube_BaseColor.png",
+         SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
+       {MaterialDefinition::EMISSIVE,
+        {"AnimatedCube_BaseColor.png",
+         SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
      }},
   };
 
index 80ed66d..3fd8fbb 100644 (file)
@@ -31,11 +31,6 @@ using namespace Dali::SceneLoader;
 
 namespace
 {
-bool EndsWith(const std::string& str, const std::string& suffix) // ends_width() is C++20
-{
-  return str.size() >= suffix.size() && str.substr(str.size() - suffix.size()).compare(suffix) == 0;
-}
-
 MaterialDefinition& NewMaterialDefinition(ResourceBundle& resources)
 {
   resources.mMaterials.push_back({});
@@ -281,8 +276,6 @@ int UtcDaliShaderDefinitionFactoryProduceShader(void)
     DALI_TEST_EQUAL(ps.shaderIdx, shaderIdx);
 
     auto& shaderDef = ctx.resources.mShaders[shaderIdx].first;
-    DALI_TEST_CHECK(EndsWith(shaderDef.mVertexShaderPath, ".vsh"));
-    DALI_TEST_CHECK(EndsWith(shaderDef.mFragmentShaderPath, ".fsh"));
     DALI_TEST_EQUAL(shaderDef.mRendererState, rendererState);
 
     uint32_t definesUnmatched = shaderDef.mDefines.size();
index e8088a3..4b917a0 100644 (file)
@@ -55,8 +55,7 @@ void utc_dali_toolkit_texture_manager_cleanup(void)
 namespace
 {
 const char* TEST_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
-
-}
+const char* TEST_MASK_FILE_NAME  = TEST_RESOURCE_DIR "/mask.png";
 
 class TestObserver : public Dali::Toolkit::TextureUploadObserver
 {
@@ -98,6 +97,45 @@ public:
   TextureSet   mTextureSet;
 };
 
+class TestObserverRemoveAndGenerateUrl : public TestObserver
+{
+public:
+  TestObserverRemoveAndGenerateUrl(TextureManager* textureManagerPtr)
+  : TestObserver(),
+    mTextureManagerPtr(textureManagerPtr)
+  {
+  }
+
+  virtual void LoadComplete(bool loadSuccess, TextureInformation textureInformation) override
+  {
+    if(textureInformation.returnType == TextureUploadObserver::ReturnType::TEXTURE)
+    {
+      mCompleteType = CompleteType::UPLOAD_COMPLETE;
+    }
+    else
+    {
+      mCompleteType = CompleteType::LOAD_COMPLETE;
+    }
+    mLoaded         = loadSuccess;
+    mObserverCalled = true;
+    mTextureSet     = textureInformation.textureSet;
+
+    // Remove during LoadComplete
+    mTextureManagerPtr->Remove(textureInformation.textureId, nullptr);
+
+    // ...And generate string which using texture id.
+    mGeneratedExternalUrl = mTextureManagerPtr->AddExternalTexture(mTextureSet);
+  }
+
+public:
+  std::string mGeneratedExternalUrl;
+
+protected:
+  TextureManager* mTextureManagerPtr; // Keep the pointer of texture manager.
+};
+
+} // namespace
+
 int UtcTextureManagerRequestLoad(void)
 {
   ToolkitTestApplication application;
@@ -164,18 +202,18 @@ int UtcTextureManagerEncodedImageBuffer(void)
   EncodedImageBuffer buffer1 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME);
   EncodedImageBuffer buffer2 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME);
 
-  std::string url1 = textureManager.AddExternalEncodedImageBuffer(buffer1);
-  std::string url2 = textureManager.AddExternalEncodedImageBuffer(buffer1);
+  std::string url1 = textureManager.AddEncodedImageBuffer(buffer1);
+  std::string url2 = textureManager.AddEncodedImageBuffer(buffer1);
   std::string url3 = VisualUrl::CreateBufferUrl(""); ///< Impossible Buffer URL. for coverage
 
   // Check if same EncodedImageBuffer get same url
   DALI_TEST_CHECK(url1 == url2);
   // Reduce reference count
-  textureManager.RemoveExternalEncodedImageBuffer(url1);
+  textureManager.RemoveEncodedImageBuffer(url1);
   // Check whethere url1 still valid
   DALI_TEST_CHECK(textureManager.GetEncodedImageBuffer(url1));
 
-  url2 = textureManager.AddExternalEncodedImageBuffer(buffer2);
+  url2 = textureManager.AddEncodedImageBuffer(buffer2);
   // Check if difference EncodedImageBuffer get difference url
   DALI_TEST_CHECK(url1 != url2);
 
@@ -250,8 +288,8 @@ int UtcTextureManagerEncodedImageBuffer(void)
   DALI_TEST_EQUALS(observer2.mObserverCalled, true, TEST_LOCATION);
   DALI_TEST_EQUALS(observer2.mCompleteType, TestObserver::CompleteType::LOAD_COMPLETE, TEST_LOCATION);
 
-  textureManager.RemoveExternalEncodedImageBuffer(url1);
-  textureManager.RemoveExternalEncodedImageBuffer(url2);
+  textureManager.RemoveEncodedImageBuffer(url1);
+  textureManager.RemoveEncodedImageBuffer(url2);
 
   // Now url1 and url2 is invalid type. mLoaded will return false
 
@@ -357,19 +395,19 @@ int UtcTextureManagerEncodedImageBufferReferenceCount(void)
   EncodedImageBuffer buffer1 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME);
   EncodedImageBuffer buffer2 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME);
 
-  std::string url1 = textureManager.AddExternalEncodedImageBuffer(buffer1);
-  std::string url2 = textureManager.AddExternalEncodedImageBuffer(buffer1);
+  std::string url1 = textureManager.AddEncodedImageBuffer(buffer1);
+  std::string url2 = textureManager.AddEncodedImageBuffer(buffer1);
 
   // Check if same EncodedImageBuffer get same url
   DALI_TEST_CHECK(url1 == url2);
 
   // Reduce reference count
-  textureManager.RemoveExternalEncodedImageBuffer(url1);
+  textureManager.RemoveEncodedImageBuffer(url1);
   // Check whethere url1 still valid
   DALI_TEST_CHECK(textureManager.GetEncodedImageBuffer(url1));
 
   // Reduce reference count
-  textureManager.RemoveExternalEncodedImageBuffer(url1);
+  textureManager.RemoveEncodedImageBuffer(url1);
   // Check whethere url1 is not valid anymore
   DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url1));
 
@@ -378,12 +416,9 @@ int UtcTextureManagerEncodedImageBufferReferenceCount(void)
   textureManager.UseExternalResource(url1);
   DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url1));
 
-  url1 = textureManager.AddExternalEncodedImageBuffer(buffer1);
-  // Check if difference EncodedImageBuffer get difference url
-  // Previous EncodedImageBuffer was deleted, so we get new url even same buffer.
-  DALI_TEST_CHECK(url1 != url2);
+  url1 = textureManager.AddEncodedImageBuffer(buffer1);
 
-  url2 = textureManager.AddExternalEncodedImageBuffer(buffer2);
+  url2 = textureManager.AddEncodedImageBuffer(buffer2);
   // Check if difference EncodedImageBuffer get difference url
   DALI_TEST_CHECK(url1 != url2);
 
@@ -445,8 +480,8 @@ int UtcTextureManagerEncodedImageBufferReferenceCount(void)
   DALI_TEST_EQUALS(observer2.mCompleteType, TestObserver::CompleteType::LOAD_COMPLETE, TEST_LOCATION);
 
   // Decrease each url's reference count.
-  textureManager.RemoveExternalEncodedImageBuffer(url1);
-  textureManager.RemoveExternalEncodedImageBuffer(url2);
+  textureManager.RemoveEncodedImageBuffer(url1);
+  textureManager.RemoveEncodedImageBuffer(url2);
 
   // url1 buffer is still have 1 reference count because it is cached.
   // But url2 not valid because it is not cached.
@@ -454,7 +489,7 @@ int UtcTextureManagerEncodedImageBufferReferenceCount(void)
   DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url2));
 
   // Check url1 buffer have 1 reference count because it is cached.
-  textureManager.RemoveExternalEncodedImageBuffer(url1);
+  textureManager.RemoveEncodedImageBuffer(url1);
   DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url1));
 
   END_TEST;
@@ -1034,3 +1069,174 @@ int UtcTextureManagerAsyncSyncAsync(void)
 
   END_TEST;
 }
+
+int UtcTextureManagerQueueRemoveDuringObserve(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcTextureManagerQueueRemoveDuringObserve");
+
+  TextureManager textureManager; // Create new texture manager
+
+  TestObserverRemoveAndGenerateUrl observer(&textureManager); // special observer for this UTC.
+
+  std::string filename(TEST_IMAGE_FILE_NAME);
+  auto        preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
+  TextureManager::TextureId textureId = textureManager.RequestLoad(
+    filename,
+    ImageDimensions(),
+    FittingMode::SCALE_TO_FILL,
+    SamplingMode::BOX_THEN_LINEAR,
+    TextureManager::UseAtlas::NO_ATLAS,
+    &observer,
+    true,
+    TextureManager::ReloadPolicy::CACHED,
+    preMultiply);
+
+  DALI_TEST_EQUALS(observer.mLoaded, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer.mObserverCalled, false, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(observer.mLoaded, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer.mObserverCalled, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION);
+
+  tet_printf("loaded textureId is %d, generated url is %s\n", static_cast<int>(textureId), observer.mGeneratedExternalUrl.c_str());
+
+  DALI_TEST_CHECK(static_cast<int>(textureId) != std::stoi(VisualUrl::GetLocation(observer.mGeneratedExternalUrl))); // Check we don't reuse textureId during observe
+
+  // Decrease external texture reference count who observer created
+  textureManager.RemoveExternalTexture(observer.mGeneratedExternalUrl);
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int UtcTextureManagerRemoveDuringApplyMasking(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcTextureManagerRemoveDuringApplyMasking");
+
+  TextureManager textureManager; // Create new texture manager
+
+  TestObserver observer1;
+  TestObserver observer2;
+
+  std::string                        filename(TEST_IMAGE_FILE_NAME);
+  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;
+
+  auto                          textureId1(TextureManager::INVALID_TEXTURE_ID);
+  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;
+
+  textureManager.LoadTexture(
+    filename,
+    ImageDimensions(),
+    FittingMode::SCALE_TO_FILL,
+    SamplingMode::BOX_THEN_LINEAR,
+    maskInfo,
+    synchronousLoading,
+    textureId1,
+    atlasRect,
+    atlasRectSize,
+    atlasingStatus,
+    loadingStatus,
+    WrapMode::DEFAULT,
+    WrapMode::DEFAULT,
+    &observer1,
+    atlasUploadObserver,
+    atlasManager,
+    true,
+    TextureManager::ReloadPolicy::CACHED,
+    preMultiply);
+
+  DALI_TEST_EQUALS(observer1.mLoaded, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer1.mObserverCalled, false, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  // Load image and mask image.
+  // Now, LoadState become MASK_APPLYING
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
+  tet_printf("Current textureId1:%d's state become MASK_APPLYING\n", static_cast<int>(textureId1));
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(observer1.mLoaded, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer1.mObserverCalled, false, TEST_LOCATION);
+
+  // Remove current textureId1. and request new texture again.
+  textureManager.Remove(textureId1, &observer1);
+  auto textureId2 = textureManager.RequestLoad(
+    filename,
+    ImageDimensions(),
+    FittingMode::SCALE_TO_FILL,
+    SamplingMode::BOX_THEN_LINEAR,
+    TextureManager::UseAtlas::NO_ATLAS,
+    &observer2,
+    true, ///< orientationCorrection
+    TextureManager::ReloadPolicy::CACHED,
+    preMultiply,
+    synchronousLoading);
+
+  application.SendNotification();
+  application.Render();
+
+  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);
+
+  tet_printf("textureId1:%d removed and textureId2:%d requested\n", static_cast<int>(textureId1), static_cast<int>(textureId2));
+
+  // ApplyMask event come back, and do nothing.
+  // CAPTION : HARD-CODING.
+  {
+    textureManager.AsyncLoadComplete(textureId1, Dali::Devel::PixelBuffer());
+    textureManager.Remove(maskInfo->mAlphaMaskId, nullptr);
+  }
+
+  application.SendNotification();
+  application.Render();
+
+  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);
+
+  // CAPTION : HARD-CODING.
+  {
+    textureManager.AsyncLoadComplete(textureId2, Dali::Devel::PixelBuffer());
+    textureManager.Remove(textureId2, &observer2);
+  }
+
+  DALI_TEST_EQUALS(observer2.mLoaded, false, TEST_LOCATION); ///< Note that we call AsyncLoadComplete hardly with empty pixelbuffer.
+  DALI_TEST_EQUALS(observer2.mObserverCalled, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer2.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION);
+
+  END_TEST;
+}
\ No newline at end of file
index 767c1f8..af42955 100644 (file)
@@ -153,8 +153,7 @@ int UtcDaliVisualUrlGif(void)
 
   DALI_TEST_EQUALS( VisualUrl::GIF, VisualUrl(".GiF").GetType(), TEST_LOCATION );
 
-  // GIFs aren't N-patch
-  DALI_TEST_EQUALS( VisualUrl::GIF, VisualUrl("foobar.9.gif").GetType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::N_PATCH, VisualUrl("foobar.9.gif").GetType(), TEST_LOCATION );
 
   DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("gif.png").GetType(), TEST_LOCATION );
   DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("gif.gif1").GetType(), TEST_LOCATION );
index d53e02a..deb9a2d 100755 (executable)
@@ -60,12 +60,13 @@ public:
    */
   enum EventType
   {
-    VOID,                ///< No event
-    PRE_EDIT,             ///< Pre-Edit changed
-    COMMIT,              ///< Commit recieved
-    DELETE_SURROUNDING,   ///< Event to delete a range of characters from the string
-    GET_SURROUNDING,      ///< Event to query string and cursor position
-    PRIVATE_COMMAND       ///< Private command sent from the input panel
+    VOID,               ///< No event
+    PRE_EDIT,           ///< Pre-Edit changed
+    COMMIT,             ///< Commit recieved
+    DELETE_SURROUNDING, ///< Event to delete a range of characters from the string
+    GET_SURROUNDING,    ///< Event to query string and cursor position
+    PRIVATE_COMMAND,    ///< Private command sent from the input panel
+    SELECTION_SET       ///< input method needs to set the selection
   };
 
   /**
@@ -141,7 +142,9 @@ public:
     : predictiveString(),
       eventName( VOID ),
       cursorOffset( 0 ),
-      numberOfChars ( 0 )
+      numberOfChars ( 0 ),
+      startIndex ( 0 ),
+      endIndex ( 0 )
     {
     };
 
@@ -157,15 +160,36 @@ public:
     : predictiveString( aPredictiveString ),
       eventName( aEventName ),
       cursorOffset( aCursorOffset ),
-      numberOfChars( aNumberOfChars )
+      numberOfChars( aNumberOfChars ),
+      startIndex ( 0 ),
+      endIndex ( 0 )
+    {
+    }
+
+    /**
+     * @brief Constructor
+     *
+     * @param[in] aEventName The name of the event from the InputMethodContext.
+     * @param[in] aStartIndex The start index of selection.
+     * @param[in] aEndIndex The end index of selection.
+     */
+    EventData(EventType aEventName, int aStartIndex, int aEndIndex)
+    : predictiveString(),
+      eventName(aEventName),
+      cursorOffset(0),
+      numberOfChars(0),
+      startIndex(aStartIndex),
+      endIndex(aEndIndex)
     {
     }
 
     // Data
     std::string predictiveString; ///< The pre-edit or commit string.
-    EventType eventName;           ///< The name of the event from the input method context.
+    EventType eventName;          ///< The name of the event from the input method context.
     int cursorOffset;             ///< Start position from the current cursor position to start deleting characters.
     int numberOfChars;            ///< number of characters to delete from the cursorOffset.
+    int startIndex;               ///< The start index of selection.
+    int endIndex;                 ///< The end index of selection.
   };
 
   /**
index ab50286..5694d9f 100644 (file)
@@ -59,6 +59,7 @@ namespace
 const char* TEST_IMAGE_FILE_NAME  = "gallery_image_01.jpg";
 const char* TEST_IMAGE_FILE_NAME2 = "gallery_image_02.jpg";
 
+// resolution: 1024*1024
 const char* TEST_IMAGE_1 = TEST_RESOURCE_DIR "/TB-gloss.png";
 const char* TEST_IMAGE_2 = TEST_RESOURCE_DIR "/tb-norm.png";
 
@@ -3105,6 +3106,7 @@ void OnResourceReadySignal02(Control control)
 ImageView gImageView1;
 ImageView gImageView2;
 ImageView gImageView3;
+ImageView gImageView4;
 
 void OnResourceReadySignal03(Control control)
 {
@@ -3136,6 +3138,66 @@ void OnSimpleResourceReadySignal(Control control)
   gResourceReadySignalCounter++;
 }
 
+int gResourceReadySignal04ComesOrder = 0;
+
+void OnResourceReadySignal04(Control control)
+{
+  gResourceReadySignalCounter++;
+  tet_printf("rc %d\n", gResourceReadySignalCounter);
+  if(gResourceReadySignalCounter == 1)
+  {
+    auto scene = gImageView1.GetParent();
+
+    // Request load something
+    // We hope this request result is return later than gImageView2.
+    gImageView3 = ImageView::New(TEST_IMAGE_1);
+    gImageView3.ResourceReadySignal().Connect(&OnResourceReadySignal04);
+    scene.Add(gImageView3);
+    gImageView4 = ImageView::New(TEST_IMAGE_2);
+    gImageView4.ResourceReadySignal().Connect(&OnResourceReadySignal04);
+    scene.Add(gImageView4);
+
+    if(control == gImageView1)
+    {
+      gResourceReadySignal04ComesOrder = 1;
+    }
+    else
+    {
+      gResourceReadySignal04ComesOrder = 2;
+    }
+  }
+  if(gResourceReadySignalCounter == 2)
+  {
+    if(gResourceReadySignal04ComesOrder == 1 && control == gImageView2)
+    {
+      // Scene off first one.
+      gImageView1.Unparent();
+
+      // Scene off second one.
+      gImageView2.Unparent();
+    }
+    else if(gResourceReadySignal04ComesOrder == 2 && control == gImageView1)
+    {
+      // Scene off first one.
+      gImageView2.Unparent();
+
+      // Scene off second one.
+      gImageView1.Unparent();
+    }
+    else
+    {
+      // We can't check that this utc fail case. just pass always when we come here.
+      gResourceReadySignal04ComesOrder = -1;
+    }
+
+    // If we don't seperate index of FreeList area
+    // and if we don't queue remove during obversing,
+    // cache index become something invalid data.
+    // In this case, some strange observer can be called.
+    // For example, gImageView4.LoadComplete will be called.
+  }
+}
+
 } // namespace
 
 int UtcDaliImageViewSetImageOnResourceReadySignal01(void)
@@ -3468,3 +3530,59 @@ int UtcDaliImageViewCheckVariousCaseSendOnResourceReadySignal(void)
 
   END_TEST;
 }
+
+int UtcDaliImageViewSetImageOnResourceReadySignal04(void)
+{
+  tet_infoline("Test texturemanager's remove queue works well within signal handler.");
+
+  ToolkitTestApplication application;
+
+  gResourceReadySignalCounter      = 0;
+  gResourceReadySignal04ComesOrder = 0;
+
+  gImageView1 = ImageView::New("invalid.jpg"); // request invalid image, to make loading failed fast.
+  gImageView1.ResourceReadySignal().Connect(&OnResourceReadySignal04);
+  application.GetScene().Add(gImageView1);
+
+  gImageView2 = ImageView::New("invalid.png"); // request invalid image, to make loading failed fast.
+  gImageView2.ResourceReadySignal().Connect(&OnResourceReadySignal04);
+  application.GetScene().Add(gImageView2);
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline("Try to load 2 invalid image");
+
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gResourceReadySignalCounter, 2, TEST_LOCATION);
+
+  tet_infoline("load done");
+
+  // We can test this UTC only if gImageView1 and gImageView2 loaded done.
+  if(gResourceReadySignal04ComesOrder == -1)
+  {
+    tet_infoline("Bad news.. gImageView3 or gImageView4 loaded faster than others. just skip this UTC");
+  }
+  else
+  {
+    // gImageView3 and gImageView4 load must not be successed yet.
+    DALI_TEST_EQUALS(gImageView3.GetRendererCount(), 0u, TEST_LOCATION);
+    DALI_TEST_EQUALS(gImageView4.GetRendererCount(), 0u, TEST_LOCATION);
+
+    application.SendNotification();
+    application.Render();
+
+    tet_infoline("Try to load 2 valid image");
+
+    DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+    DALI_TEST_EQUALS(gResourceReadySignalCounter, 4, TEST_LOCATION);
+
+    tet_infoline("load done");
+
+    // gImageView3 and gImageView4 load must be successed now.
+    DALI_TEST_EQUALS(gImageView3.GetRendererAt(0).GetTextures().GetTextureCount(), 1u, TEST_LOCATION);
+    DALI_TEST_EQUALS(gImageView4.GetRendererAt(0).GetTextures().GetTextureCount(), 1u, TEST_LOCATION);
+  }
+
+  END_TEST;
+}
index d0bb94b..05ae1c4 100644 (file)
@@ -2307,4 +2307,47 @@ int UtcDaliKeyboardFocusManagerWithHide(void)
 
 
   END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerWithVisible(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardFocusManagerWithVisible");
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  // Create the first actor and add it to the stage
+  Actor first = Actor::New();
+  first.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true);
+  application.GetScene().Add(first);
+
+  // Create the second actor and add it to the first actor.
+  Actor second = Actor::New();
+  second.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true);
+  first.Add(second);
+
+  // Check that no actor is being focused yet.
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+
+  // Check that the focus is set on the first actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+
+  // Set visible false.
+  first.SetProperty(Actor::Property::VISIBLE, false);
+
+  // Check that it will fail to set focus on the second actor as it's not focusable
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == false);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+
+  // Set visible true.
+  first.SetProperty(Actor::Property::VISIBLE, true);
+
+  // Check that the focus is set on the second actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+
+  END_TEST;
 }
\ No newline at end of file
index b86f96b..3e8b0de 100644 (file)
@@ -1599,6 +1599,83 @@ int utcDaliTextFieldTextChangedWithInputMethodContext(void)
   END_TEST;
 }
 
+int utcDaliTextFieldSelectionWithInputMethodContext(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldSelectionWithInputMethodContext");
+  TextField field = TextField::New();
+  DALI_TEST_CHECK(field);
+
+  field.SetProperty(TextField::Property::TEXT, "Hello world");
+
+  application.GetScene().Add(field);
+
+  // connect to the selection changed signal.
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  DevelTextField::SelectionChangedSignal(field).Connect(&TestSelectionChangedCallback);
+  bool selectionChangedSignal = false;
+  field.ConnectSignal(testTracker, "selectionChanged", CallbackFunctor(&selectionChangedSignal));
+
+  // get InputMethodContext
+  std::string                   text;
+  InputMethodContext::EventData imfEvent;
+  InputMethodContext            inputMethodContext = DevelTextField::GetInputMethodContext(field);
+
+  field.SetKeyInputFocus();
+  field.SetProperty(DevelTextField::Property::ENABLE_EDITING, true);
+
+  // input text
+  gSelectionChangedCallbackCalled = false;
+  imfEvent                        = InputMethodContext::EventData(InputMethodContext::SELECTION_SET, 1, 4);
+  inputMethodContext.EventReceivedSignal().Emit(inputMethodContext, imfEvent);
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK(gSelectionChangedCallbackCalled);
+
+  DALI_TEST_EQUALS(field.GetProperty(DevelTextField::Property::SELECTED_TEXT_START).Get<int>(), 1, TEST_LOCATION);
+  DALI_TEST_EQUALS(field.GetProperty(DevelTextField::Property::SELECTED_TEXT_END).Get<int>(), 4, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int utcDaliTextFieldPositionWithInputMethodContext(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldPositionWithInputMethodContext");
+  TextField field = TextField::New();
+  DALI_TEST_CHECK(field);
+
+  field.SetProperty(TextField::Property::TEXT, "Hello world");
+
+  application.GetScene().Add(field);
+
+  // connect to the selection changed signal.
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  DevelTextField::CursorPositionChangedSignal(field).Connect(&TestCursorPositionChangedCallback);
+  bool cursorPositionChangedSignal = false;
+  field.ConnectSignal(testTracker, "cursorPositionChanged", CallbackFunctor(&cursorPositionChangedSignal));
+
+  // get InputMethodContext
+  std::string                   text;
+  InputMethodContext::EventData imfEvent;
+  InputMethodContext            inputMethodContext = DevelTextField::GetInputMethodContext(field);
+
+  field.SetKeyInputFocus();
+  field.SetProperty(DevelTextField::Property::ENABLE_EDITING, true);
+
+  // input text
+  gCursorPositionChangedCallbackCalled = false;
+  imfEvent                             = InputMethodContext::EventData(InputMethodContext::SELECTION_SET, 2, 2);
+  inputMethodContext.EventReceivedSignal().Emit(inputMethodContext, imfEvent);
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK(gCursorPositionChangedCallbackCalled);
+
+  DALI_TEST_EQUALS(field.GetProperty(DevelTextField::Property::PRIMARY_CURSOR_POSITION).Get<int>(), 2, TEST_LOCATION);
+
+  END_TEST;
+}
+
 // Negative test for the textChanged signal.
 int utcDaliTextFieldTextChangedN(void)
 {
index f5bd6b9..e074c28 100644 (file)
@@ -317,6 +317,7 @@ struct TextureInfo
   Ref<gltf2::Texture> mTexture;
   uint32_t            mTexCoord = 0;
   float               mScale    = 1.f;
+  float               mStrength = 1.f;
 
   operator bool() const
   {
diff --git a/dali-scene-loader/internal/graphics/shaders/default-physically-based-shader.frag b/dali-scene-loader/internal/graphics/shaders/default-physically-based-shader.frag
new file mode 100644 (file)
index 0000000..2581ad6
--- /dev/null
@@ -0,0 +1,183 @@
+#version 300 es
+
+#ifdef HIGHP
+  precision highp float;
+#else
+  precision mediump float;
+#endif
+
+#ifdef THREE_TEX
+#ifdef GLTF_CHANNELS
+// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#pbrmetallicroughnessmetallicroughnesstexture
+#define METALLIC b
+#define ROUGHNESS g
+#else //GLTF_CHANNELS
+#define METALLIC r
+#define ROUGHNESS a
+#endif //GLTF_CHANNELS
+#endif //THREE_TEX
+
+#ifdef THREE_TEX
+  uniform sampler2D sAlbedoAlpha;
+  uniform sampler2D sMetalRoughness;
+  uniform sampler2D sNormal;
+
+#ifdef ALPHA_TEST
+  uniform float uAlphaThreshold;
+#endif //ALPHA_TEST
+
+#else
+  uniform sampler2D sAlbedoMetal;
+  uniform sampler2D sNormalRoughness;
+#endif
+
+#ifdef OCCLUSION
+  uniform sampler2D sOcclusion;
+  uniform float uOcclusionStrength;
+#endif
+
+#ifdef EMISSIVE
+  uniform sampler2D sEmissive;
+  uniform vec3 uEmissiveFactor;
+#endif
+
+uniform samplerCube sDiffuse;
+uniform samplerCube sSpecular;
+
+// Number of mip map levels in the texture
+uniform float uMaxLOD;
+
+// Transformation matrix of the cubemap texture
+uniform mat4 uCubeMatrix;
+
+uniform vec4 uColor;
+uniform float uMetallicFactor;
+uniform float uRoughnessFactor;
+
+//IBL Light intensity
+uniform float uIblIntensity;
+
+// TODO: Multiple texture coordinate will be supported.
+in vec2 vUV;
+in vec3 vNormal;
+in vec3 vTangent;
+in vec3 vViewVec;
+
+out vec4 FragColor;
+
+// Functions for BRDF calculation come from
+// https://www.unrealengine.com/blog/physically-based-shading-on-mobile
+// Based on the paper by Dimitar Lazarov
+// http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf
+vec3 EnvBRDFApprox( vec3 SpecularColor, float Roughness, float NoV )
+{
+  const vec4 c0 = vec4( -1.0, -0.0275, -0.572, 0.022 );
+  const vec4 c1 = vec4( 1.0, 0.0425, 1.04, -0.04 );
+  vec4 r = Roughness * c0 + c1;
+  float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
+  vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;
+
+  return SpecularColor * AB.x + AB.y;
+}
+
+void main()
+{
+  // We get information from the maps (albedo, normal map, roughness, metalness
+  // I access the maps in the order they will be used
+#ifdef THREE_TEX
+  vec4 albedoAlpha = texture(sAlbedoAlpha, vUV.st);
+  float alpha = albedoAlpha.a;
+#ifdef ALPHA_TEST
+  if (alpha <= uAlphaThreshold)
+  {
+    discard;
+  }
+#endif //ALPHA_TEST
+  vec3 albedoColor = albedoAlpha.rgb * uColor.rgb;
+
+  vec4 metalRoughness = texture(sMetalRoughness, vUV.st);
+  float metallic = metalRoughness.METALLIC * uMetallicFactor;
+  float roughness = metalRoughness.ROUGHNESS * uRoughnessFactor;
+
+  vec3 normalMap = texture(sNormal, vUV.st).rgb;
+#else  //THREE_TEX
+  vec4 albedoMetal = texture(sAlbedoMetal, vUV.st);
+  vec3 albedoColor = albedoMetal.rgb * uColor.rgb;
+  float metallic = albedoMetal.a * uMetallicFactor;
+
+  vec4 normalRoughness = texture(sNormalRoughness, vUV.st);
+  vec3 normalMap = normalRoughness.rgb;
+  float roughness = normalRoughness.a * uRoughnessFactor;
+#endif
+  //Normalize vectors
+  vec3 normal = normalize(vNormal);
+  vec3 tangent = normalize(vTangent);
+
+  // NOTE: normal and tangent have to be orthogonal for the result of the cross()
+  // product to be a unit vector. We might find that we need to normalize().
+  vec3 bitangent = cross(normal, tangent);
+
+  vec3 viewVec = normalize(vViewVec);
+
+  // Create Inverse Local to world matrix
+  mat3 vInvTBN = mat3(tangent, bitangent, normal);
+
+  // Get normal map info in world space
+  normalMap = normalize(normalMap - 0.5);
+  vec3 newNormal = vInvTBN * normalMap.rgb;
+
+  // Calculate normal dot view vector
+  float NoV = max(dot(newNormal, -viewVec), 0.0);
+
+  // Reflect vector
+  vec3 reflectionVec = reflect(viewVec, newNormal);
+
+  //transform it now to environment coordinates (used when the environment rotates)
+  vec3 reflecCube = (uCubeMatrix * vec4( reflectionVec, 0.0 ) ).xyz;
+  reflecCube = normalize( reflecCube );
+
+  //transform it now to environment coordinates
+  vec3 normalCube = ( uCubeMatrix * vec4( newNormal, 0.0 ) ).xyz;
+  normalCube = normalize( normalCube );
+
+  // Get irradiance from diffuse cubemap
+  vec3 irradiance = texture( sDiffuse, normalCube ).rgb;
+
+  // Access reflection color using roughness value
+  float finalLod = mix( 0.0, uMaxLOD - 2.0, roughness);
+  vec3 reflectionColor = textureLod(sSpecular, reflecCube, finalLod).rgb;
+
+  // We are supposed to be using DielectricColor (0.04) of a plastic (almost everything)
+  // http://blog.selfshadow.com/publications/s2014-shading-course/hoffman/s2014_pbs_physics_math_slides.pdf
+  // however that seems to prevent achieving very dark tones (i.e. get dark gray blacks).
+  vec3 DiffuseColor = albedoColor - albedoColor * metallic;  // 1 mad
+  vec3 SpecularColor = mix( vec3(0.04), albedoColor, metallic); // 2 mad
+
+  // Calculate specular color using Magic Function (takes original roughness and normal dot view).
+  vec3 specColor =  reflectionColor.rgb * EnvBRDFApprox(SpecularColor, roughness, NoV );
+
+  // Multiply the result by albedo texture and do energy conservation
+  vec3 diffuseColor = irradiance * DiffuseColor;
+
+  // Final color is the sum of the diffuse and specular term
+  vec3 finalColor = diffuseColor + specColor;
+
+  finalColor = sqrt( finalColor ) * uIblIntensity;
+
+
+#ifdef OCCLUSION
+  float ao = texture(sOcclusion, vUV.st).r;
+  finalColor = mix( finalColor, finalColor * ao, uOcclusionStrength );
+#endif
+
+#ifdef EMISSIVE
+  vec3 emissive = texture( sEmissive, vUV.st ).rgb * uEmissiveFactor;
+  finalColor += emissive;
+#endif
+
+#ifdef THREE_TEX
+  FragColor = vec4( finalColor, alpha );
+#else //THREE_TEX
+  FragColor = vec4( finalColor, 1.0 );
+#endif //THREE_TEX
+}
diff --git a/dali-scene-loader/internal/graphics/shaders/default-physically-based-shader.vert b/dali-scene-loader/internal/graphics/shaders/default-physically-based-shader.vert
new file mode 100644 (file)
index 0000000..e9381c5
--- /dev/null
@@ -0,0 +1,149 @@
+#version 300 es
+
+#ifdef HIGHP
+  precision highp float;
+#else
+  precision mediump float;
+#endif
+
+in vec3 aPosition;
+in vec2 aTexCoord;
+in vec3 aNormal;
+in vec3 aTangent;
+
+#ifdef MORPH
+  uniform sampler2D sBlendShapeGeometry;
+#endif
+
+out vec2 vUV;
+out vec3 vNormal;
+out vec3 vTangent;
+out vec3 vViewVec;
+
+uniform highp mat4 uMvpMatrix;
+uniform highp mat4 uViewMatrix;
+uniform mat3 uNormalMatrix;
+uniform mat4 uModelMatrix;
+uniform mat4 uModelView;
+uniform mat4 uProjection;
+
+#ifdef SKINNING
+  in vec4 aJoints;
+  in vec4 aWeights;
+  #define MAX_BONES 64
+  uniform mat4 uBone[MAX_BONES];
+#endif
+
+#ifdef MORPH
+#define MAX_BLEND_SHAPE_NUMBER 128
+uniform int uNumberOfBlendShapes;                                   ///< Total number of blend shapes loaded.
+uniform float uBlendShapeWeight[MAX_BLEND_SHAPE_NUMBER];            ///< The weight of each blend shape.
+#ifdef MORPH_VERSION_2_0
+uniform float uBlendShapeUnnormalizeFactor;                         ///< Factor used to unnormalize the geometry of the blend shape.
+#else
+uniform float uBlendShapeUnnormalizeFactor[MAX_BLEND_SHAPE_NUMBER]; ///< Factor used to unnormalize the geometry of the blend shape.
+#endif
+uniform int uBlendShapeComponentSize;                               ///< The size in the texture of either the vertices, normals or tangents. Used to calculate the offset to address them.
+#endif
+
+void main()
+{
+  vec4 position = vec4(aPosition, 1.0);
+  vec3 normal = aNormal;
+  vec3 tangent = aTangent;
+
+#ifdef MORPH
+  int width = textureSize( sBlendShapeGeometry, 0 ).x;
+
+  int blendShapeBufferOffset = 0;
+  for( int index = 0; index < uNumberOfBlendShapes; ++index )
+  {
+#ifdef MORPH_POSITION
+    // Calculate the index to retrieve the geometry from the texture.
+    int vertexId = gl_VertexID + blendShapeBufferOffset;
+    int x = vertexId % width;
+    int y = vertexId / width;
+
+    vec3 diff = vec3(0.0);
+    // Retrieves the blend shape geometry from the texture, unnormalizes it and multiply by the weight.
+    if( 0.0 != uBlendShapeWeight[index] )
+    {
+#ifdef MORPH_VERSION_2_0
+       float unnormalizeFactor = uBlendShapeUnnormalizeFactor;
+#else
+       float unnormalizeFactor = uBlendShapeUnnormalizeFactor[index];
+#endif
+
+      diff = uBlendShapeWeight[index] * unnormalizeFactor * ( texelFetch( sBlendShapeGeometry, ivec2(x, y), 0 ).xyz - 0.5 );
+    }
+
+    position.xyz += diff;
+
+    blendShapeBufferOffset += uBlendShapeComponentSize;
+#endif
+
+#ifdef MORPH_NORMAL
+    // Calculate the index to retrieve the normal from the texture.
+    vertexId = gl_VertexID + blendShapeBufferOffset;
+    x = vertexId % width;
+    y = vertexId / width;
+
+    // Retrieves the blend shape normal from the texture, unnormalizes it and multiply by the weight.
+    if( 0.0 != uBlendShapeWeight[index] )
+    {
+      diff = uBlendShapeWeight[index] * 2.0 * ( texelFetch( sBlendShapeGeometry, ivec2(x, y), 0 ).xyz - 0.5 );
+    }
+
+    normal += diff.xyz;
+
+    blendShapeBufferOffset += uBlendShapeComponentSize;
+#endif
+
+#ifdef MORPH_TANGENT
+    // Calculate the index to retrieve the tangent from the texture.
+    vertexId = gl_VertexID + blendShapeBufferOffset;
+    x = vertexId % width;
+    y = vertexId / width;
+
+    // Retrieves the blend shape tangent from the texture, unnormalizes it and multiply by the weight.
+    if( 0.0 != uBlendShapeWeight[index] )
+    {
+      diff = uBlendShapeWeight[index] * 2.0 * ( texelFetch( sBlendShapeGeometry, ivec2(x, y), 0 ).xyz - 0.5 );
+    }
+
+    tangent += diff.xyz;
+
+    blendShapeBufferOffset += uBlendShapeComponentSize;
+#endif
+  }
+
+#endif
+
+#ifdef SKINNING
+  mat4 bone = uBone[int(aJoints.x)] * aWeights.x +
+    uBone[int(aJoints.y)] * aWeights.y +
+    uBone[int(aJoints.z)] * aWeights.z +
+    uBone[int(aJoints.w)] * aWeights.w;
+  position = bone * position;
+  normal = (bone * vec4(normal, 0.0)).xyz;
+  tangent = (bone * vec4(tangent, 0.0)).xyz;
+#endif
+
+  vec4 vPosition = uModelMatrix * position;
+
+  vNormal = normalize(uNormalMatrix * normal);
+
+  vTangent = normalize(uNormalMatrix * tangent);
+
+
+  vec4 viewPosition = uViewMatrix * vPosition;
+  gl_Position = uProjection * viewPosition;
+
+#ifdef FLIP_V
+  vUV = vec2(aTexCoord.x, 1.0 - aTexCoord.y);
+#else
+  vUV = aTexCoord;
+#endif
+
+  vViewVec = viewPosition.xyz;
+}
index 923d0e4..be7e538 100644 (file)
@@ -157,7 +157,8 @@ const auto TEXURE_READER = std::move(js::Reader<gt::Texture>()
 const auto TEXURE_INFO_READER = std::move(js::Reader<gt::TextureInfo>()
                                             .Register(*js::MakeProperty("index", gt::RefReader<gt::Document>::Read<gt::Texture, &gt::Document::mTextures>, &gt::TextureInfo::mTexture))
                                             .Register(*js::MakeProperty("texCoord", js::Read::Number<uint32_t>, &gt::TextureInfo::mTexCoord))
-                                            .Register(*js::MakeProperty("scale", js::Read::Number<float>, &gt::TextureInfo::mScale)));
+                                            .Register(*js::MakeProperty("scale", js::Read::Number<float>, &gt::TextureInfo::mScale))
+                                            .Register(*js::MakeProperty("strength", js::Read::Number<float>, &gt::TextureInfo::mStrength)));
 
 const auto MATERIAL_PBR_READER = std::move(js::Reader<gt::Material::Pbr>()
                                              .Register(*js::MakeProperty("baseColorFactor", gt::ReadDaliVector<Vector4>, &gt::Material::Pbr::mBaseColorFactor))
@@ -440,7 +441,7 @@ void ConvertMaterial(const gt::Material& m, decltype(ResourceBundle::mMaterials)
 
   matDef.mColor = pbr.mBaseColorFactor;
 
-  matDef.mTextureStages.reserve(!!pbr.mBaseColorTexture + !!pbr.mMetallicRoughnessTexture + !!m.mNormalTexture);
+  matDef.mTextureStages.reserve(!!pbr.mBaseColorTexture + !!pbr.mMetallicRoughnessTexture + !!m.mNormalTexture + !!m.mOcclusionTexture + !!m.mEmissiveTexture);
   if(pbr.mBaseColorTexture)
   {
     const auto semantic = MaterialDefinition::ALBEDO;
@@ -470,6 +471,23 @@ void ConvertMaterial(const gt::Material& m, decltype(ResourceBundle::mMaterials)
   }
 
   // TODO: handle doubleSided
+  if(m.mOcclusionTexture)
+  {
+    const auto semantic = MaterialDefinition::OCCLUSION;
+    matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(m.mOcclusionTexture)});
+    // TODO: and there had better be one
+    matDef.mFlags |= semantic;
+    matDef.mOcclusionStrength = m.mOcclusionTexture.mStrength;
+  }
+
+  if(m.mEmissiveTexture)
+  {
+    const auto semantic = MaterialDefinition::EMISSIVE;
+    matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(m.mEmissiveTexture)});
+    // TODO: and there had better be one
+    matDef.mFlags |= semantic;
+    matDef.mEmissiveFactor = m.mEmissiveFactor;
+  }
 
   outMaterials.emplace_back(std::move(matDef), TextureSet());
 }
index 3c7a391..1342ced 100644 (file)
@@ -110,7 +110,9 @@ MaterialDefinition::LoadRaw(const std::string& imagesPath) const
   RawData raw;
 
   const bool hasTransparency = MaskMatch(mFlags, TRANSPARENCY);
-  uint32_t   numBuffers      = mTextureStages.size() + (hasTransparency ? !CheckTextures(ALBEDO) + !CheckTextures(METALLIC | ROUGHNESS) + !CheckTextures(NORMAL) : !CheckTextures(ALBEDO | METALLIC) + !CheckTextures(NORMAL | ROUGHNESS));
+  // Why we add additional count here?
+  uint32_t numBuffers = mTextureStages.size() + (hasTransparency ? !CheckTextures(ALBEDO) + !CheckTextures(METALLIC | ROUGHNESS) + !CheckTextures(NORMAL)
+                                                                 : !CheckTextures(ALBEDO | METALLIC) + !CheckTextures(NORMAL | ROUGHNESS));
   if(numBuffers == 0)
   {
     return raw;
@@ -210,7 +212,7 @@ MaterialDefinition::LoadRaw(const std::string& imagesPath) const
     }
   }
 
-  // Extra textures. TODO: emissive, occlusion etc.
+  // Extra textures.
   if(checkStage(SUBSURFACE))
   {
     raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags});
@@ -223,6 +225,12 @@ MaterialDefinition::LoadRaw(const std::string& imagesPath) const
     ++iTexture;
   }
 
+  if(checkStage(EMISSIVE))
+  {
+    raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags});
+    ++iTexture;
+  }
+
   return raw;
 }
 
index 80e93e7..e36f74b 100644 (file)
@@ -219,10 +219,12 @@ struct DALI_SCENE_LOADER_API MaterialDefinition
 public: // DATA
   uint32_t mFlags = 0x0;
 
-  Index                     mEnvironmentIdx = 0;
-  Vector4                   mColor          = Color::WHITE;
-  float                     mMetallic       = 1.f;
-  float                     mRoughness      = 1.f;
+  Index                     mEnvironmentIdx    = 0;
+  Vector4                   mColor             = Color::WHITE;
+  Vector3                   mEmissiveFactor    = Vector3::ZERO;
+  float                     mMetallic          = 1.f;
+  float                     mRoughness         = 1.f;
+  float                     mOcclusionStrength = 1.f;
   std::vector<TextureStage> mTextureStages;
 };
 
index 45e0b23..e8f6b82 100644 (file)
@@ -153,6 +153,14 @@ void ModelNode::OnCreate(const NodeDefinition& node, NodeDefinition::CreateParam
   auto& matDef = resources.mMaterials[mMaterialIdx].first;
   actor.RegisterProperty("uMetallicFactor", matDef.mMetallic);
   actor.RegisterProperty("uRoughnessFactor", matDef.mRoughness);
+  if(matDef.mFlags & MaterialDefinition::OCCLUSION)
+  {
+    actor.RegisterProperty("uOcclusionStrength", matDef.mOcclusionStrength);
+  }
+  if(matDef.mFlags & MaterialDefinition::EMISSIVE)
+  {
+    actor.RegisterProperty("uEmissiveFactor", matDef.mEmissiveFactor);
+  }
 
   Index envIdx = matDef.mEnvironmentIdx;
   actor.RegisterProperty("uIblIntensity", resources.mEnvironmentMaps[envIdx].first.mIblIntensity);
index bd6b168..6f9ab4e 100644 (file)
@@ -56,8 +56,6 @@ struct ResourceReceiver : IResourceReceiver
   }
 };
 
-const std::string PBR_SHADER_NAME = "dli_pbr";
-
 void RetrieveBlendShapeComponents(const std::vector<MeshDefinition::BlendShape>& blendShapes, bool& hasPositions, bool& hasNormals, bool& hasTangents)
 {
   for(const auto& blendShape : blendShapes)
@@ -72,9 +70,6 @@ uint64_t HashNode(const NodeDefinition& nodeDef, const MaterialDefinition& mater
 {
   Hash hash;
 
-  // note: could be per vertex / fragment component - in WatchViewer, these have the same name.
-  hash.Add(PBR_SHADER_NAME);
-
   const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
   hash.Add(hasTransparency);
 
@@ -101,6 +96,11 @@ uint64_t HashNode(const NodeDefinition& nodeDef, const MaterialDefinition& mater
     hash.Add("OCCL" /*USION*/);
   }
 
+  if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
+  {
+    hash.Add("EMIS" /*SIVE*/);
+  }
+
   if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
   {
     hash.Add("GLTF" /*_CHANNELS*/);
@@ -192,8 +192,7 @@ Index ShaderDefinitionFactory::ProduceShader(const NodeDefinition& nodeDef)
   }
 
   ShaderDefinition shaderDef;
-  shaderDef.mVertexShaderPath   = PBR_SHADER_NAME + ".vsh";
-  shaderDef.mFragmentShaderPath = PBR_SHADER_NAME + ".fsh";
+  shaderDef.mUseBuiltInShader = true;
   shaderDef.mRendererState      = RendererState::DEPTH_TEST | RendererState::DEPTH_WRITE | RendererState::CULL_BACK;
 
   auto&      materialDef     = *receiver.mMaterialDef;
@@ -222,12 +221,17 @@ Index ShaderDefinitionFactory::ProduceShader(const NodeDefinition& nodeDef)
     shaderDef.mDefines.push_back("SSS");
   }
 
-  if(MaskMatch(receiver.mMaterialDef->mFlags, MaterialDefinition::OCCLUSION))
+  if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
   {
     shaderDef.mDefines.push_back("OCCLUSION");
   }
 
-  if(MaskMatch(receiver.mMaterialDef->mFlags, MaterialDefinition::GLTF_CHANNELS))
+  if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
+  {
+    shaderDef.mDefines.push_back("EMISSIVE");
+  }
+
+  if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
   {
     shaderDef.mDefines.push_back("GLTF_CHANNELS");
   }
index 73c18ba..71024f3 100644 (file)
@@ -18,6 +18,7 @@
 // INTERNAL INCLUDES
 #include "dali-scene-loader/public-api/shader-definition.h"
 #include "dali-scene-loader/public-api/utils.h"
+#include <dali-scene-loader/internal/graphics/builtin-shader-extern-gen.h>
 
 namespace Dali
 {
@@ -36,7 +37,8 @@ ShaderDefinition::ShaderDefinition(const ShaderDefinition& other)
   mFragmentShaderPath(other.mFragmentShaderPath),
   mDefines(other.mDefines),
   mHints(other.mHints),
-  mUniforms(other.mUniforms)
+  mUniforms(other.mUniforms),
+  mUseBuiltInShader(false)
 {
 }
 
@@ -80,28 +82,38 @@ ShaderDefinition::LoadRaw(const std::string& shadersPath) const
 {
   RawData raw;
 
-  bool fail               = false;
-  raw.mVertexShaderSource = LoadTextFile((shadersPath + mVertexShaderPath).c_str(), &fail);
-  if(!fail)
+  bool fail = false;
+  if(!mUseBuiltInShader)
   {
-    raw.mFragmentShaderSource = LoadTextFile((shadersPath + mFragmentShaderPath).c_str(), &fail);
+    raw.mVertexShaderSource = LoadTextFile((shadersPath + mVertexShaderPath).c_str(), &fail);
     if(!fail)
     {
-      for(auto definevar : mDefines)
+      raw.mFragmentShaderSource = LoadTextFile((shadersPath + mFragmentShaderPath).c_str(), &fail);
+      if(fail)
       {
-        ApplyDefine(raw.mVertexShaderSource, definevar);
-        ApplyDefine(raw.mFragmentShaderSource, definevar);
+        ExceptionFlinger(ASSERT_LOCATION) << "Failed to load shader source from '" << shadersPath + mFragmentShaderPath << "'.";
       }
     }
     else
     {
-      ExceptionFlinger(ASSERT_LOCATION) << "Failed to load shader source from '" << shadersPath + mFragmentShaderPath << "'.";
+      ExceptionFlinger(ASSERT_LOCATION) << "Failed to load shader source from '" << shadersPath + mVertexShaderPath << "'.";
     }
   }
   else
   {
-    ExceptionFlinger(ASSERT_LOCATION) << "Failed to load shader source from '" << shadersPath + mVertexShaderPath << "'.";
+    raw.mVertexShaderSource   = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_VERT.data();
+    raw.mFragmentShaderSource = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_FRAG.data();
+  }
+
+  if(!fail)
+  {
+    for(auto definevar : mDefines)
+    {
+      ApplyDefine(raw.mVertexShaderSource, definevar);
+      ApplyDefine(raw.mFragmentShaderSource, definevar);
+    }
   }
+
   return raw;
 }
 
index d7f390b..386a0c9 100644 (file)
@@ -79,8 +79,8 @@ public: // DATA
   std::string              mFragmentShaderPath;
   std::vector<std::string> mDefines;
   std::vector<std::string> mHints;
-
-  Property::Map mUniforms;
+  Property::Map            mUniforms;
+  bool                     mUseBuiltInShader{false};
 };
 
 } // namespace SceneLoader
index 1f0effb..756a7a5 100644 (file)
@@ -80,15 +80,9 @@ public:
     // Scene doesn't use both of point and directional light\r
     NONE = 0,\r
     // Scene use point light\r
-    POINT_LIGHT,\r
+    POINT_LIGHT = 1,\r
     // Scene use directional light\r
-    DIRECTIONAL_LIGHT,\r
-    // Scene use Image Based Lighting\r
-    IMAGE_BASED_LIGHT,\r
-    // Scene use Image Based Lighting and point light\r
-    IMAGE_BASED_LIGHT_AND_POINT_LIGHT,\r
-    // Scene use Image Based Lighting and directional light\r
-    IMAGE_BASED_LIGHT_AND_DIRECTIONAL_LIGHT\r
+    DIRECTIONAL_LIGHT = 2\r
   };\r
 \r
   /**\r
index 2c8de12..55dfd8d 100644 (file)
@@ -1509,7 +1509,7 @@ Actor Loader::AddNode(Scene3dView& scene3dView, uint32_t index)
     VERTEX_SHADER += SHADER_GLTF_PHYSICALLY_BASED_SHADER_VERT.data();
     FRAGMENT_SHADER = SHADER_GLTF_GLES_VERSION_300_DEF.data();
 
-    bool useIBL = (scene3dView.GetLightType() >= Toolkit::Scene3dView::LightType::IMAGE_BASED_LIGHT);
+    bool useIBL = scene3dView.HasImageBasedLighting();
     if(isMaterial)
     {
       MaterialInfo materialInfo = mMaterialArray[meshInfo.materialsIdx];
@@ -1592,11 +1592,14 @@ Actor Loader::AddNode(Scene3dView& scene3dView, uint32_t index)
     actor.RotateBy(orientation);
     actor.SetProperty(Actor::Property::POSITION, translation);
 
-    shader.RegisterProperty("uLightType", (scene3dView.GetLightType() & ~Toolkit::Scene3dView::LightType::IMAGE_BASED_LIGHT));
+    float hasLightSource = static_cast<float>(!!(scene3dView.GetLightType() & (Toolkit::Scene3dView::LightType::POINT_LIGHT | Toolkit::Scene3dView::LightType::DIRECTIONAL_LIGHT)));
+    float isPointLight = static_cast<float>(!!(scene3dView.GetLightType() & Toolkit::Scene3dView::LightType::POINT_LIGHT));
+    shader.RegisterProperty("uHasLightSource", hasLightSource);
+    shader.RegisterProperty("uIsPointLight", isPointLight);
     shader.RegisterProperty("uLightVector", scene3dView.GetLightVector());
     shader.RegisterProperty("uLightColor", scene3dView.GetLightColor());
 
-    actor.RegisterProperty("uIsColor", meshInfo.attribute.COLOR.size() > 0);
+    actor.RegisterProperty("uHasVertexColor", meshInfo.attribute.COLOR.size() > 0 ? 1.0f : 0.0f);
     if(isMaterial)
     {
       MaterialInfo materialInfo = mMaterialArray[meshInfo.materialsIdx];
@@ -1605,15 +1608,15 @@ Actor Loader::AddNode(Scene3dView& scene3dView, uint32_t index)
 
       if(materialInfo.alphaMode == "OPAQUE")
       {
-        actor.RegisterProperty("alphaMode", 0);
+        actor.RegisterProperty("uAlphaMode", 0.0f);
       }
       else if(materialInfo.alphaMode == "MASK")
       {
-        actor.RegisterProperty("alphaMode", 1);
+        actor.RegisterProperty("uAlphaMode", 1.0f);
       }
       else
       {
-        actor.RegisterProperty("alphaMode", 2);
+        actor.RegisterProperty("uAlphaMode", 2.0f);
       }
       actor.RegisterProperty("alphaCutoff", materialInfo.alphaCutoff);
 
index aa8438a..6231b64 100644 (file)
@@ -54,7 +54,8 @@ Scene3dView::Scene3dView()
   mAnimationArray(),
   mLightType(Toolkit::Scene3dView::LightType::NONE),
   mLightVector(Vector3::ONE),
-  mLightColor(Vector3::ONE)
+  mLightColor(Vector3::ONE),
+  mUseIBL(false)
 {
 }
 
@@ -130,20 +131,16 @@ bool Scene3dView::PlayAnimations()
 
 bool Scene3dView::SetLight(Toolkit::Scene3dView::LightType type, Vector3 lightVector, Vector3 lightColor)
 {
-  if(type > Toolkit::Scene3dView::LightType::DIRECTIONAL_LIGHT)
-  {
-    return false;
-  }
-
-  mLightType = static_cast<Toolkit::Scene3dView::LightType>(
-    (mLightType >= Toolkit::Scene3dView::LightType::IMAGE_BASED_LIGHT) ? Toolkit::Scene3dView::LightType::IMAGE_BASED_LIGHT + type : type);
-
+  mLightType = type;
   mLightVector = lightVector;
   mLightColor  = lightColor;
 
   for(auto&& shader : mShaderArray)
   {
-    shader.RegisterProperty("uLightType", (GetLightType() & ~Toolkit::Scene3dView::LightType::IMAGE_BASED_LIGHT));
+    float hasLightSource = static_cast<float>(!!(GetLightType() & (Toolkit::Scene3dView::LightType::POINT_LIGHT | Toolkit::Scene3dView::LightType::DIRECTIONAL_LIGHT)));
+    float isPointLight = static_cast<float>(!!(GetLightType() & Toolkit::Scene3dView::LightType::POINT_LIGHT));
+    shader.RegisterProperty("uHasLightSource", hasLightSource);
+    shader.RegisterProperty("uIsPointLight", isPointLight);
     shader.RegisterProperty("uLightVector", lightVector);
     shader.RegisterProperty("uLightColor", lightColor);
   }
@@ -203,8 +200,6 @@ void Scene3dView::UploadTextureFace(Texture& texture, Devel::PixelBuffer pixelBu
 
 void Scene3dView::SetCubeMap(const std::string& diffuseTexturePath, const std::string& specularTexturePath, Vector4 scaleFactor)
 {
-  mLightType = Toolkit::Scene3dView::LightType::IMAGE_BASED_LIGHT;
-
   // BRDF texture
   const std::string imageDirPath = AssetManager::GetDaliImagePath();
   const std::string imageBrdfUrl = imageDirPath + IMAGE_BRDF_FILE_NAME;
@@ -235,6 +230,7 @@ void Scene3dView::SetCubeMap(const std::string& diffuseTexturePath, const std::s
   mSpecularTexture.GenerateMipmaps();
 
   mIBLScaleFactor = scaleFactor;
+  mUseIBL = true;
 }
 
 bool Scene3dView::SetDefaultCamera(const Dali::Camera::Type type, const float nearPlane, const Vector3 cameraPosition)
@@ -318,6 +314,11 @@ Texture Scene3dView::GetSpecularTexture()
   return mSpecularTexture;
 }
 
+bool Scene3dView::HasImageBasedLighting()
+{
+  return mUseIBL;
+}
+
 Texture Scene3dView::GetDiffuseTexture()
 {
   return mDiffuseTexture;
index 6dbe859..bc731d3 100644 (file)
@@ -185,6 +185,11 @@ public:
    */\r
   Texture GetSpecularTexture();\r
 \r
+  /**\r
+   * @brief Get whether the scene has image based rendering or not.\r
+   */\r
+  bool HasImageBasedLighting();\r
+\r
 private:\r
   /**\r
    * @brief Get Cropped image buffer.\r
@@ -232,6 +237,7 @@ private:
   Texture mBRDFTexture;     // BRDF texture for the PBR rendering\r
   Texture mSpecularTexture; // Specular cube map texture\r
   Texture mDiffuseTexture;  // Diffuse cube map texture\r
+  bool    mUseIBL;\r
 \r
 private:\r
   // Undefined copy constructor.\r
index a64690e..d0daa9f 100644 (file)
@@ -205,53 +205,44 @@ bool KeyboardFocusManager::DoSetCurrentFocusActor(Actor actor)
 {
   bool success = false;
 
-  // If the parent's KEYBOARD_FOCUSABLE_CHILDREN is false, it cannot have focus.
-  if(actor)
+  // Check whether the actor is in the stage and is keyboard focusable.
+  if(actor &&
+     actor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) &&
+     actor.GetProperty<bool>(DevelActor::Property::USER_INTERACTION_ENABLED) &&
+     actor.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE) &&
+     actor.GetProperty<bool>(Actor::Property::VISIBLE))
   {
+    // If the parent's KEYBOARD_FOCUSABLE_CHILDREN is false or VISIBLE is false, it cannot have focus.
     Actor parent = actor.GetParent();
     while(parent)
     {
-      if(!parent.GetProperty<bool>(DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN))
+      if(!parent.GetProperty<bool>(DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN) || !parent.GetProperty<bool>(Actor::Property::VISIBLE))
       {
-        DALI_LOG_INFO(gLogFilter, Debug::General, "[%s:%d] Parent Actor has KEYBOARD_FOCUSABLE_CHILDREN false,\n", __FUNCTION__, __LINE__);
+        DALI_LOG_INFO(gLogFilter, Debug::General, "[%s:%d] Parent Actor has KEYBOARD_FOCUSABLE_CHILDREN false or VISIBLE false,\n", __FUNCTION__, __LINE__);
         return false;
       }
       parent = parent.GetParent();
     }
-  }
 
-  if(actor && actor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) && actor.GetProperty<bool>(DevelActor::Property::USER_INTERACTION_ENABLED) && actor.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
-  {
-    Integration::SceneHolder currentWindow = Integration::SceneHolder::Get(actor);
+    // If developer set focus on same actor, doing nothing
+    Actor currentFocusedActor = GetCurrentFocusActor();
+    if(actor == currentFocusedActor)
+    {
+      return true;
+    }
 
+    Integration::SceneHolder currentWindow = Integration::SceneHolder::Get(actor);
     if(currentWindow.GetRootLayer() != mCurrentFocusedWindow.GetHandle())
     {
       Layer rootLayer       = currentWindow.GetRootLayer();
       mCurrentFocusedWindow = rootLayer;
     }
-  }
-
-  Actor currentFocusedActor = GetCurrentFocusActor();
-
-  // If developer set focus on same actor, doing nothing
-  if(actor == currentFocusedActor)
-  {
-    if(!actor)
-    {
-      return false;
-    }
-    return true;
-  }
 
-  // Check whether the actor is in the stage and is keyboard focusable.
-  if(actor && actor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) && actor.GetProperty<bool>(DevelActor::Property::USER_INTERACTION_ENABLED) && actor.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
-  {
     if((mIsFocusIndicatorShown == SHOW) && (mEnableFocusIndicator == ENABLE))
     {
       actor.Add(GetFocusIndicatorActor());
     }
 
-
     Toolkit::Control currentlyFocusedControl = Toolkit::Control::DownCast(currentFocusedActor);
     if(currentlyFocusedControl)
     {
index cefd19e..9477e40 100644 (file)
@@ -1,13 +1,13 @@
 uniform lowp vec3 uLightColor;
 uniform lowp vec4 uBaseColorFactor;
 uniform lowp vec2 uMetallicRoughnessFactors;
-uniform lowp int alphaMode;
 uniform lowp float alphaCutoff;
+uniform lowp float uAlphaMode;
+uniform lowp float uHasLightSource;
 
 in lowp vec2 vUV[2];
 in lowp mat3 vTBN;
 in lowp vec4 vColor;
-flat in int visLight;
 in highp vec3 vLightDirection;
 in highp vec3 vPositionToCamera;
 
@@ -30,20 +30,20 @@ const float c_MinRoughness = 0.04;
 vec3 getNormal()
 {
 #ifdef TEXTURE_NORMAL
-  lowp vec3 n = texture( uNormalSampler, vUV[uNormalTexCoordIndex] ).rgb;
-  n = normalize( vTBN * ( ( 2.0 * n - 1.0 ) * vec3( uNormalScale, uNormalScale, 1.0 ) ) );
+  lowp vec3 n = texture(uNormalSampler, vUV[uNormalTexCoordIndex]).rgb;
+  n = normalize(vTBN * ((2.0 * n - 1.0) * vec3(uNormalScale, uNormalScale, 1.0)));
 #else
   lowp vec3 n = normalize( vTBN[2].xyz );
 #endif
   return n;
 }
 
-vec3 specularReflection( PBRInfo pbrInputs )
+vec3 specularReflection(PBRInfo pbrInputs)
 {
-  return pbrInputs.reflectance0 + ( pbrInputs.reflectance90 - pbrInputs.reflectance0 ) * pow( clamp( 1.0 - pbrInputs.VdotH, 0.0, 1.0 ), 5.0 );
+  return pbrInputs.reflectance0 + (pbrInputs.reflectance90 - pbrInputs.reflectance0) * pow(clamp(1.0 - pbrInputs.VdotH, 0.0, 1.0), 5.0);
 }
 
-float geometricOcclusion( PBRInfo pbrInputs )
+float geometricOcclusion(PBRInfo pbrInputs)
 {
   mediump float NdotL = pbrInputs.NdotL;
   mediump float NdotV = pbrInputs.NdotV;
@@ -61,7 +61,7 @@ float microfacetDistribution(PBRInfo pbrInputs)
   return roughnessSq / (M_PI * f * f);
 }
 
-vec3 linear( vec3 color )
+vec3 linear(vec3 color)
 {
   return pow(color,vec3(2.2));
 }
@@ -96,13 +96,13 @@ void main()
   lowp vec4 baseColor = vColor * uBaseColorFactor;
 #endif
 
-  if( alphaMode == 0 )
+  if(uAlphaMode < 0.5f)
   {
     baseColor.w = 1.0;
   }
-  else if( alphaMode == 1 )
+  else if(uAlphaMode < 1.5f)
   {
-    if( baseColor.w >= alphaCutoff )
+    if(baseColor.w >= alphaCutoff)
     {
       baseColor.w = 1.0;
     }
@@ -150,7 +150,7 @@ void main()
 
   // Calculate the shading terms for the microfacet specular shading model
   lowp vec3 color = vec3(0.0);
-  if( visLight == 1 )
+  if( uHasLightSource > 0.5f )
   {
     lowp vec3 F = specularReflection( pbrInputs );
     lowp float G = geometricOcclusion( pbrInputs );
index 6628865..095e839 100644 (file)
@@ -9,51 +9,34 @@ uniform mediump vec3 uSize;
 uniform mediump mat4 uModelMatrix;
 uniform mediump mat4 uViewMatrix;
 uniform mediump mat4 uProjection;
-uniform lowp int uLightType;
 uniform mediump vec3 uLightVector;
-uniform lowp int uIsColor;
+uniform lowp float uIsPointLight;
+uniform lowp float uHasVertexColor;
 
 out lowp vec2 vUV[2];
 out lowp mat3 vTBN;
 out lowp vec4 vColor;
-flat out int visLight;
 out highp vec3 vLightDirection;
 out highp vec3 vPositionToCamera;
 
 void main()
 {
   highp vec4 invY = vec4(1.0, -1.0, 1.0, 1.0);
-  highp vec4 positionW = uModelMatrix * vec4( aPosition * uSize, 1.0 );
-  highp vec4 positionV = uViewMatrix * ( invY * positionW );
+  highp vec4 positionW = uModelMatrix * vec4(aPosition * uSize, 1.0);
+  highp vec4 positionV = uViewMatrix * (invY * positionW);
 
-  vPositionToCamera = transpose( mat3( uViewMatrix ) ) * ( -vec3( positionV.xyz / positionV.w ) );
+  vPositionToCamera = transpose(mat3(uViewMatrix)) * (-vec3(positionV.xyz / positionV.w));
   vPositionToCamera *= invY.xyz;
 
   lowp vec3 bitangent = cross(aNormal, aTangent.xyz) * aTangent.w;
-  vTBN = mat3( uModelMatrix ) * mat3(aTangent.xyz, bitangent, aNormal);
+  vTBN = mat3(uModelMatrix) * mat3(aTangent.xyz, bitangent, aNormal);
 
   vUV[0] = aTexCoord0;
   vUV[1] = aTexCoord1;
 
-  visLight = 1;
-  if( uLightType == 1 )
-  {
-    vLightDirection = ( invY.xyz * uLightVector ) - ( positionW.xyz / positionW.w );
-  }
-  else if( uLightType == 2 )
-  {
-    vLightDirection = -( invY.xyz * uLightVector );
-  }
-  else
-  {
-    visLight = 0;
-  }
-
-  vColor = vec4( 1.0 );
-  if( uIsColor == 1 )
-  {
-    vColor = aVertexColor;
-  }
+  vLightDirection = mix(-(invY.xyz * uLightVector), (invY.xyz * uLightVector) - (positionW.xyz / positionW.w), uIsPointLight);
+
+  vColor = mix(vec4(1.0f), aVertexColor, uHasVertexColor);
 
   gl_Position = uProjection * positionV; // needs w for proper perspective correction
   gl_Position = gl_Position/gl_Position.w;
index 0742d3c..fae9fc1 100644 (file)
@@ -42,7 +42,7 @@ ImageUrl::ImageUrl(const EncodedImageBuffer& encodedImageBuffer)
   if(visualFactory)
   {
     auto& textureManager = GetImplementation(visualFactory).GetTextureManager();
-    mUrl                 = textureManager.AddExternalEncodedImageBuffer(encodedImageBuffer);
+    mUrl                 = textureManager.AddEncodedImageBuffer(encodedImageBuffer);
   }
 }
 
@@ -60,7 +60,7 @@ ImageUrl::~ImageUrl()
       }
       else if(VisualUrl::BUFFER == VisualUrl::GetProtocolType(mUrl))
       {
-        textureManager.RemoveExternalEncodedImageBuffer(mUrl);
+        textureManager.RemoveEncodedImageBuffer(mUrl);
       }
     }
   }
index d5c41a1..1d4be23 100644 (file)
@@ -809,6 +809,21 @@ InputMethodContext::CallbackData Controller::EventHandler::OnInputMethodContextE
       retrieveCursor = true;
       break;
     }
+    case InputMethodContext::SELECTION_SET:
+    {
+      uint32_t start = static_cast<uint32_t>(inputMethodContextEvent.startIndex);
+      uint32_t end = static_cast<uint32_t>(inputMethodContextEvent.endIndex);
+      if(start == end)
+      {
+        controller.SetPrimaryCursorPosition(start, true);
+      }
+      else
+      {
+        controller.SelectText(start, end);
+      }
+
+      break;
+    }
     case InputMethodContext::VOID:
     {
       // do nothing
index 9524c44..a561161 100644 (file)
@@ -47,12 +47,43 @@ extern Debug::Filter* gTextureManagerLogFilter; ///< Define at texture-manager-i
                                                                  "Unknown"
 // clang-format on
 #endif
-namespace
+
+// Due to the compile issue, this specialized template code must be defined top of this code.
+template<>
+void TextureCacheManager::RemoveTextureInfoByIndex<TextureCacheManager::EncodedImageBufferInfoContainerType>(TextureCacheManager::EncodedImageBufferInfoContainerType& cacheContainer, const TextureCacheManager::TextureCacheIndex& removeContainerIndex)
 {
-} // Anonymous namespace
+  // Swap last data of cacheContainer.
+  if(static_cast<std::size_t>(removeContainerIndex.GetIndex() + 1) < cacheContainer.size())
+  {
+    // First, change the cache index infomations inside of converter
+    mTextureIdConverter[cacheContainer.back().bufferId] = static_cast<std::uint32_t>(removeContainerIndex);
+
+    // After change converter, swap the value between current data and last data.
+    std::swap(cacheContainer[removeContainerIndex.GetIndex()], cacheContainer.back());
+  }
+
+  // Now we can assume that latest data should be removed. pop_back.
+  cacheContainer.pop_back();
+}
+
+template<class ContainerType>
+void TextureCacheManager::RemoveTextureInfoByIndex(ContainerType& cacheContainer, const TextureCacheManager::TextureCacheIndex& removeContainerIndex)
+{
+  // Swap last data of cacheContainer.
+  if(static_cast<std::size_t>(removeContainerIndex.GetIndex() + 1) < cacheContainer.size())
+  {
+    // First, change the cache index infomations inside of converter
+    mTextureIdConverter[cacheContainer.back().textureId] = static_cast<std::uint32_t>(removeContainerIndex);
+
+    // After change converter, swap the value between current data and last data.
+    std::swap(cacheContainer[removeContainerIndex.GetIndex()], cacheContainer.back());
+  }
+
+  // Now we can assume that latest data should be removed. pop_back.
+  cacheContainer.pop_back();
+}
 
 TextureCacheManager::TextureCacheManager()
-: mCurrentTextureId(0)
 {
 }
 
@@ -63,50 +94,73 @@ TextureCacheManager::~TextureCacheManager()
 VisualUrl TextureCacheManager::GetVisualUrl(const TextureCacheManager::TextureId& textureId)
 {
   VisualUrl         visualUrl("");
-  TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
+  TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
 
-  if(cacheIndex != INVALID_CACHE_INDEX)
+  switch(static_cast<TextureCacheIndexType>(cacheIndex.detailValue.type))
   {
-    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached texture id=%d, textureId=%d\n", cacheIndex, textureId);
+    case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL:
+    {
+      DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached texture index=%d, textureId=%d\n", cacheIndex.GetIndex(), textureId);
 
-    TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex]);
-    visualUrl = cachedTextureInfo.url;
+      TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
+      visualUrl = cachedTextureInfo.url;
+      break;
+    }
+    case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE:
+    {
+      DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached external texture index=%d, textureId=%d\n", cacheIndex.GetIndex(), textureId);
+      visualUrl = VisualUrl::CreateTextureUrl(std::to_string(textureId));
+      break;
+    }
+    case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_BUFFER:
+    {
+      DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached buffer index=%d, bufferId=%d\n", cacheIndex.GetIndex(), textureId);
+      visualUrl = VisualUrl::CreateBufferUrl(std::to_string(textureId));
+      break;
+    }
+    default:
+    {
+      break;
+    }
   }
+
   return visualUrl;
 }
 
 TextureCacheManager::LoadState TextureCacheManager::GetTextureState(const TextureCacheManager::TextureId& textureId)
 {
-  LoadState loadState = TextureCacheManager::LoadState::NOT_STARTED;
+  LoadState         loadState  = TextureCacheManager::LoadState::NOT_STARTED;
+  TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
 
-  TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
-  if(cacheIndex != INVALID_CACHE_INDEX)
-  {
-    TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex]);
-    loadState = cachedTextureInfo.loadState;
-  }
-  else
+  switch(static_cast<TextureCacheIndexType>(cacheIndex.detailValue.type))
   {
-    for(auto&& elem : mExternalTextures)
+    case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL:
     {
-      if(elem.textureId == textureId)
-      {
-        loadState = LoadState::UPLOADED;
-        break;
-      }
+      TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
+      loadState = cachedTextureInfo.loadState;
+      break;
+    }
+    case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE:
+    {
+      loadState = LoadState::UPLOADED;
+      break;
+    }
+    default:
+    {
+      break;
     }
   }
+
   return loadState;
 }
 
 TextureCacheManager::LoadState TextureCacheManager::GetTextureStateInternal(const TextureCacheManager::TextureId& textureId)
 {
-  LoadState loadState = TextureCacheManager::LoadState::NOT_STARTED;
-
+  LoadState         loadState  = TextureCacheManager::LoadState::NOT_STARTED;
   TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
   if(cacheIndex != INVALID_CACHE_INDEX)
   {
-    TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex]);
+    TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
     loadState = cachedTextureInfo.loadState;
   }
 
@@ -115,66 +169,63 @@ TextureCacheManager::LoadState TextureCacheManager::GetTextureStateInternal(cons
 
 TextureSet TextureCacheManager::GetTextureSet(const TextureCacheManager::TextureId& textureId)
 {
-  TextureSet textureSet; // empty handle
+  TextureSet        textureSet; // empty handle
+  TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
 
-  TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
-  if(cacheIndex != INVALID_CACHE_INDEX)
+  switch(static_cast<TextureCacheIndexType>(cacheIndex.detailValue.type))
   {
-    TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex]);
-    textureSet = cachedTextureInfo.textureSet;
-  }
-  else
-  {
-    for(auto&& elem : mExternalTextures)
+    case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL:
     {
-      if(elem.textureId == textureId)
-      {
-        textureSet = elem.textureSet;
-        break;
-      }
+      TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
+      textureSet = cachedTextureInfo.textureSet;
+      break;
+    }
+    case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE:
+    {
+      textureSet = mExternalTextures[cacheIndex.GetIndex()].textureSet;
+      break;
+    }
+    default:
+    {
+      break;
     }
   }
+
   return textureSet;
 }
 
 TextureSet TextureCacheManager::GetExternalTextureSet(const TextureCacheManager::TextureId& textureId)
 {
-  TextureSet textureSet; // empty handle
-  for(auto&& elem : mExternalTextures)
+  TextureSet        textureSet; // empty handle
+  TextureCacheIndex cacheIndex = GetCacheIndexFromExternalTextureId(textureId);
+  if(cacheIndex != INVALID_CACHE_INDEX)
   {
-    if(elem.textureId == textureId)
-    {
-      textureSet = elem.textureSet;
-      break;
-    }
+    textureSet = mExternalTextures[cacheIndex.GetIndex()].textureSet;
   }
   return textureSet;
 }
 
-EncodedImageBuffer TextureCacheManager::GetEncodedImageBuffer(const TextureCacheManager::TextureId& textureId)
+EncodedImageBuffer TextureCacheManager::GetEncodedImageBuffer(const TextureCacheManager::TextureId& bufferId)
 {
   EncodedImageBuffer encodedImageBuffer; // empty handle
-  for(auto&& elem : mEncodedBufferTextures)
+  TextureCacheIndex  cacheIndex = GetCacheIndexFromEncodedImageBufferId(bufferId);
+  if(cacheIndex != INVALID_CACHE_INDEX)
   {
-    if(elem.textureId == textureId)
-    {
-      encodedImageBuffer = elem.encodedImageBuffer;
-      break;
-    }
+    encodedImageBuffer = mEncodedImageBuffers[cacheIndex.GetIndex()].encodedImageBuffer;
   }
   return encodedImageBuffer;
 }
 
-EncodedImageBuffer TextureCacheManager::GetEncodedImageBuffer(const std::string& url)
+EncodedImageBuffer TextureCacheManager::GetEncodedImageBuffer(const VisualUrl& url)
 {
   EncodedImageBuffer encodedImageBuffer; // empty handle
-  if(url.size() > 0 && VisualUrl::BUFFER == VisualUrl::GetProtocolType(url))
+  if(url.IsValid() && VisualUrl::BUFFER == url.GetProtocolType())
   {
-    std::string location = VisualUrl::GetLocation(url);
+    std::string location = url.GetLocation();
     if(location.size() > 0u)
     {
-      TextureId targetId = std::stoi(location);
-      return GetEncodedImageBuffer(targetId);
+      TextureId bufferId = std::stoi(location);
+      return GetEncodedImageBuffer(bufferId);
     }
   }
   return encodedImageBuffer;
@@ -182,86 +233,130 @@ EncodedImageBuffer TextureCacheManager::GetEncodedImageBuffer(const std::string&
 
 std::string TextureCacheManager::AddExternalTexture(const TextureSet& textureSet)
 {
-  TextureCacheManager::ExternalTextureInfo info(GenerateUniqueTextureId(), textureSet);
-  mExternalTextures.emplace_back(info);
-  return VisualUrl::CreateTextureUrl(std::to_string(info.textureId));
+  TextureId textureId = GenerateTextureId(TextureCacheIndex(TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE, mExternalTextures.size()));
+
+  TextureCacheManager::ExternalTextureInfo textureInfo(textureId, textureSet);
+  mExternalTextures.emplace_back(textureInfo);
+
+  DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::AddExternalTexture() : New texture registered. textureId:%d\n", textureInfo.textureId);
+
+  return VisualUrl::CreateTextureUrl(std::to_string(textureInfo.textureId));
 }
 
-std::string TextureCacheManager::AddExternalEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer)
+std::string TextureCacheManager::AddEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer)
 {
   // Duplication check
-  for(auto&& elem : mEncodedBufferTextures)
+  TextureHash       bufferHash       = static_cast<TextureHash>(encodedImageBuffer.GetHash());
+  TextureCacheIndex bufferCacheIndex = FindCachedEncodedImageBuffer(bufferHash, encodedImageBuffer);
+  if(bufferCacheIndex != INVALID_CACHE_INDEX)
   {
-    if(elem.encodedImageBuffer == encodedImageBuffer)
-    {
-      // If same buffer added, increase reference count and return.
-      elem.referenceCount++;
-      return VisualUrl::CreateBufferUrl(std::to_string(elem.textureId));
-    }
+    EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[bufferCacheIndex.GetIndex()]);
+
+    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::AddExternalEncodedImageBuffer() : Increase reference. bufferId:%d, cache index:%d, reference:%d\n", bufferInfo.bufferId, bufferCacheIndex.GetIndex(), static_cast<int>(bufferInfo.referenceCount));
+
+    // If same buffer added, increase reference count and return.
+    bufferInfo.referenceCount++;
+    return VisualUrl::CreateBufferUrl(std::to_string(bufferInfo.bufferId));
   }
-  TextureCacheManager::EncodedBufferTextureInfo info(GenerateUniqueTextureId(), encodedImageBuffer);
-  mEncodedBufferTextures.emplace_back(info);
-  return VisualUrl::CreateBufferUrl(std::to_string(info.textureId));
+
+  TextureId bufferId = GenerateTextureId(TextureCacheIndex(TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_BUFFER, mEncodedImageBuffers.size()));
+
+  TextureCacheManager::EncodedImageBufferInfo info(bufferId, bufferHash, encodedImageBuffer);
+  mEncodedImageBuffers.emplace_back(info);
+
+  // Insert TextureHashContainer
+  // Find exist list -or- Create new list.
+  std::vector<TextureId>& idList = mTextureHashContainer[bufferHash];
+  // We already assume that list doesn't contain id. just emplace back
+  idList.emplace_back(bufferId);
+
+  DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::AddExternalEncodedImageBuffer() : New buffer regested. bufferId:%d\n", info.bufferId);
+
+  return VisualUrl::CreateBufferUrl(std::to_string(info.bufferId));
 }
 
-TextureSet TextureCacheManager::RemoveExternalTexture(const std::string& url)
+TextureSet TextureCacheManager::RemoveExternalTexture(const VisualUrl& url)
 {
-  if(url.size() > 0u)
+  TextureSet        textureSet;
+  bool              removeTextureInfo  = false;
+  TextureCacheIndex removeTextureIndex = INVALID_CACHE_INDEX;
+  if(url.IsValid())
   {
-    if(VisualUrl::TEXTURE == VisualUrl::GetProtocolType(url))
+    if(VisualUrl::TEXTURE == url.GetProtocolType())
     {
       // get the location from the Url
-      std::string location = VisualUrl::GetLocation(url);
+      std::string location = url.GetLocation();
       if(location.size() > 0u)
       {
-        TextureId  id  = std::stoi(location);
-        const auto end = mExternalTextures.end();
-        for(auto iter = mExternalTextures.begin(); iter != end; ++iter)
+        TextureId textureId = std::stoi(location);
+        removeTextureIndex  = GetCacheIndexFromExternalTextureId(textureId);
+        if(removeTextureIndex != INVALID_CACHE_INDEX)
         {
-          if(iter->textureId == id)
+          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));
+          textureSet = textureInfo.textureSet;
+          if(--(textureInfo.referenceCount) <= 0)
           {
-            auto textureSet = iter->textureSet;
-            if(--(iter->referenceCount) <= 0)
-            {
-              mExternalTextures.erase(iter);
-            }
-            return textureSet;
+            removeTextureInfo = true;
+            // id life is finished. Remove it at converter
+            mTextureIdConverter.Remove(textureId);
           }
         }
       }
     }
   }
-  return TextureSet();
+
+  // Post removal process to avoid mExternalTextures reference problems.
+  if(removeTextureInfo)
+  {
+    // Swap last data of mExternalTextures, and pop_back.
+    RemoveTextureInfoByIndex(mExternalTextures, removeTextureIndex);
+  }
+  return textureSet;
 }
 
-EncodedImageBuffer TextureCacheManager::RemoveExternalEncodedImageBuffer(const std::string& url)
+EncodedImageBuffer TextureCacheManager::RemoveEncodedImageBuffer(const VisualUrl& url)
 {
-  if(url.size() > 0u)
+  EncodedImageBuffer encodedImageBuffer;
+  bool               removeBufferInfo  = false;
+  TextureCacheIndex  removeBufferIndex = INVALID_CACHE_INDEX;
+  if(url.IsValid())
   {
-    if(VisualUrl::BUFFER == VisualUrl::GetProtocolType(url))
+    if(VisualUrl::BUFFER == url.GetProtocolType())
     {
       // get the location from the Url
-      std::string location = VisualUrl::GetLocation(url);
+      std::string location = url.GetLocation();
       if(location.size() > 0u)
       {
-        TextureId  id  = std::stoi(location);
-        const auto end = mEncodedBufferTextures.end();
-        for(auto iter = mEncodedBufferTextures.begin(); iter != end; ++iter)
+        TextureId bufferId = std::stoi(location);
+        removeBufferIndex  = GetCacheIndexFromEncodedImageBufferId(bufferId);
+
+        if(removeBufferIndex != INVALID_CACHE_INDEX)
         {
-          if(iter->textureId == id)
+          EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[removeBufferIndex.GetIndex()]);
+          DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::RemoveEncodedImageBuffer(url:%s) bufferId:%d reference:%d\n", url.GetUrl().c_str(), bufferId, static_cast<int>(bufferInfo.referenceCount));
+
+          encodedImageBuffer = bufferInfo.encodedImageBuffer;
+          if(--(bufferInfo.referenceCount) <= 0)
           {
-            auto encodedImageBuffer = iter->encodedImageBuffer;
-            if(--(iter->referenceCount) <= 0)
-            {
-              mEncodedBufferTextures.erase(iter);
-            }
-            return encodedImageBuffer;
+            removeBufferInfo = true;
+            // Step 1. remove current textureId information in mTextureHashContainer.
+            RemoveHashId(bufferInfo.bufferHash, bufferId);
+            // Step 2. id life is finished. Remove it at converter
+            mTextureIdConverter.Remove(bufferId);
           }
         }
       }
     }
   }
-  return EncodedImageBuffer();
+
+  // Post removal process to avoid mEncodedImageBuffers reference problems.
+  if(removeBufferInfo)
+  {
+    // Step 3. swap last data of mEncodedImageBuffers, and pop_back.
+    RemoveTextureInfoByIndex(mEncodedImageBuffers, removeBufferIndex);
+  }
+  return encodedImageBuffer;
 }
 
 void TextureCacheManager::UseExternalResource(const VisualUrl& url)
@@ -271,14 +366,15 @@ void TextureCacheManager::UseExternalResource(const VisualUrl& url)
     std::string location = url.GetLocation();
     if(location.size() > 0u)
     {
-      TextureId id = std::stoi(location);
-      for(auto&& elem : mExternalTextures)
+      TextureId         id         = std::stoi(location);
+      TextureCacheIndex cacheIndex = GetCacheIndexFromExternalTextureId(id);
+      if(cacheIndex != INVALID_CACHE_INDEX)
       {
-        if(elem.textureId == id)
-        {
-          elem.referenceCount++;
-          return;
-        }
+        ExternalTextureInfo& textureInfo(mExternalTextures[cacheIndex.GetIndex()]);
+        DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::UseExternalResource(url:%s) type:TEXTURE, location:%s, reference:%d\n", url.GetUrl().c_str(), url.GetLocation().c_str(), static_cast<int>(textureInfo.referenceCount));
+
+        textureInfo.referenceCount++;
+        return;
       }
     }
   }
@@ -287,49 +383,108 @@ void TextureCacheManager::UseExternalResource(const VisualUrl& url)
     std::string location = url.GetLocation();
     if(location.size() > 0u)
     {
-      TextureId id = std::stoi(location);
-      for(auto&& elem : mEncodedBufferTextures)
+      TextureId         id         = std::stoi(location);
+      TextureCacheIndex cacheIndex = GetCacheIndexFromEncodedImageBufferId(id);
+      if(cacheIndex != INVALID_CACHE_INDEX)
       {
-        if(elem.textureId == id)
-        {
-          elem.referenceCount++;
-          return;
-        }
+        EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[cacheIndex.GetIndex()]);
+        DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::UseExternalResource(url:%s) type:BUFFER, location:%s, reference:%d\n", url.GetUrl().c_str(), url.GetLocation().c_str(), static_cast<int>(bufferInfo.referenceCount));
+
+        bufferInfo.referenceCount++;
+        return;
       }
     }
   }
 }
 
-TextureCacheManager::TextureId TextureCacheManager::GenerateUniqueTextureId()
+TextureCacheManager::TextureId TextureCacheManager::GenerateTextureId(const TextureCacheIndex& textureCacheIndex)
 {
-  return mCurrentTextureId++;
+  return mTextureIdConverter.Add(static_cast<std::uint32_t>(textureCacheIndex.indexValue));
 }
 
 TextureCacheManager::TextureCacheIndex TextureCacheManager::GetCacheIndexFromId(const TextureCacheManager::TextureId& textureId)
 {
-  const TextureCacheIndex size = static_cast<TextureCacheIndex>(mTextureInfoContainer.size());
+  if(textureId == INVALID_TEXTURE_ID) return INVALID_CACHE_INDEX;
 
-  for(TextureCacheIndex i = 0; i < size; ++i)
+  TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
+  if(DALI_UNLIKELY(cacheIndex.detailValue.type != TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL))
   {
-    if(mTextureInfoContainer[i].textureId == textureId)
+    return INVALID_CACHE_INDEX;
+  }
+
+  DALI_ASSERT_DEBUG(static_cast<std::size_t>(cacheIndex.GetIndex()) < mTextureInfoContainer.size());
+
+  return cacheIndex;
+}
+
+TextureCacheManager::TextureCacheIndex TextureCacheManager::GetCacheIndexFromExternalTextureId(const TextureCacheManager::TextureId& textureId)
+{
+  if(textureId == INVALID_TEXTURE_ID) return INVALID_CACHE_INDEX;
+
+  TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
+  if(DALI_UNLIKELY(cacheIndex.detailValue.type != TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE))
+  {
+    return INVALID_CACHE_INDEX;
+  }
+
+  DALI_ASSERT_DEBUG(static_cast<std::size_t>(cacheIndex.GetIndex()) < mExternalTextures.size());
+
+  return cacheIndex;
+}
+
+TextureCacheManager::TextureCacheIndex TextureCacheManager::GetCacheIndexFromEncodedImageBufferId(const TextureCacheManager::TextureId& bufferId)
+{
+  if(bufferId == INVALID_TEXTURE_ID) return INVALID_CACHE_INDEX;
+
+  TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(bufferId)]);
+  if(DALI_UNLIKELY(cacheIndex.detailValue.type != TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_BUFFER))
+  {
+    return INVALID_CACHE_INDEX;
+  }
+
+  DALI_ASSERT_DEBUG(static_cast<std::size_t>(cacheIndex.GetIndex()) < mEncodedImageBuffers.size());
+
+  return cacheIndex;
+}
+
+TextureCacheManager::TextureCacheIndex TextureCacheManager::FindCachedEncodedImageBuffer(const TextureCacheManager::TextureHash& hash, const EncodedImageBuffer& encodedImageBuffer)
+{
+  // Iterate through our hashes to find a match.
+  const auto& hashIterator = mTextureHashContainer.find(hash);
+  if(hashIterator != mTextureHashContainer.cend())
+  {
+    for(const auto& id : hashIterator->second)
     {
-      return i;
+      // We have a match, now we check all the original parameters in case of a hash collision.
+      TextureCacheIndex cacheIndex = GetCacheIndexFromEncodedImageBufferId(id);
+      if(cacheIndex != INVALID_CACHE_INDEX)
+      {
+        EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[cacheIndex.GetIndex()]);
+
+        if(bufferInfo.encodedImageBuffer == encodedImageBuffer)
+        {
+          // The found encoded image buffer.
+          return cacheIndex;
+        }
+      }
     }
   }
 
+  // Default to an invalid ID, in case we do not find a match.
   return INVALID_CACHE_INDEX;
 }
 
 TextureCacheManager::TextureHash TextureCacheManager::GenerateHash(
-  const std::string&                    url,
+  const VisualUrl&                      url,
   const Dali::ImageDimensions&          size,
   const Dali::FittingMode::Type&        fittingMode,
   const Dali::SamplingMode::Type&       samplingMode,
   const TextureCacheManager::UseAtlas&  useAtlas,
-  const TextureCacheManager::TextureId& maskTextureId)
+  const TextureCacheManager::TextureId& maskTextureId,
+  const bool&                           cropToMask)
 {
-  std::vector<std::uint8_t> hashTarget(url.begin(), url.end());
-  const size_t              urlLength = url.length();
+  std::vector<std::uint8_t> hashTarget(url.GetUrl().begin(), url.GetUrl().end());
+  const size_t              urlLength = hashTarget.size();
   const uint16_t            width     = size.GetWidth();
   const uint16_t            height    = size.GetWidth();
 
@@ -374,7 +529,7 @@ TextureCacheManager::TextureHash TextureCacheManager::GenerateHash(
   if(maskTextureId != INVALID_TEXTURE_ID)
   {
     auto textureIdIndex = hashTarget.size();
-    hashTarget.resize(hashTarget.size() + sizeof(TextureId));
+    hashTarget.resize(hashTarget.size() + sizeof(TextureId) + 1u);
     std::uint8_t* hashTargetPtr = reinterpret_cast<std::uint8_t*>(&(hashTarget[textureIdIndex]));
 
     // Append the texture id to the end of the URL byte by byte:
@@ -385,6 +540,7 @@ TextureCacheManager::TextureHash TextureCacheManager::GenerateHash(
       *hashTargetPtr++ = saltedMaskTextureId & 0xff;
       saltedMaskTextureId >>= 8u;
     }
+    *hashTargetPtr++ = (cropToMask ? 'C' : 'M');
   }
 
   return Dali::CalculateHash(hashTarget);
@@ -392,55 +548,80 @@ TextureCacheManager::TextureHash TextureCacheManager::GenerateHash(
 
 TextureCacheManager::TextureCacheIndex TextureCacheManager::FindCachedTexture(
   const TextureCacheManager::TextureHash&    hash,
-  const std::string&                         url,
+  const VisualUrl&                           url,
   const Dali::ImageDimensions&               size,
   const Dali::FittingMode::Type&             fittingMode,
   const Dali::SamplingMode::Type&            samplingMode,
   const TextureCacheManager::UseAtlas&       useAtlas,
   const TextureCacheManager::TextureId&      maskTextureId,
+  const bool&                                cropToMask,
   const TextureCacheManager::MultiplyOnLoad& preMultiplyOnLoad,
-  bool                                       isAnimatedImage)
+  const bool&                                isAnimatedImage)
 {
-  // Default to an invalid ID, in case we do not find a match.
-  TextureCacheIndex cacheIndex = INVALID_CACHE_INDEX;
-
   // Iterate through our hashes to find a match.
-  const TextureCacheIndex count = static_cast<TextureCacheIndex>(mTextureInfoContainer.size());
-  for(TextureCacheIndex i = 0u; i < count; ++i)
+  const auto& hashIterator = mTextureHashContainer.find(hash);
+  if(hashIterator != mTextureHashContainer.cend())
   {
-    if(mTextureInfoContainer[i].hash == hash)
+    for(const auto& textureId : hashIterator->second)
     {
       // We have a match, now we check all the original parameters in case of a hash collision.
-      TextureInfo& textureInfo(mTextureInfoContainer[i]);
-
-      if((url == textureInfo.url.GetUrl()) &&
-         (useAtlas == textureInfo.useAtlas) &&
-         (maskTextureId == textureInfo.maskTextureId) &&
-         (size == textureInfo.desiredSize) &&
-         (isAnimatedImage == textureInfo.isAnimatedImageFormat) &&
-         ((size.GetWidth() == 0 && size.GetHeight() == 0) ||
-          (fittingMode == textureInfo.fittingMode &&
-           samplingMode == textureInfo.samplingMode)))
+      TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
+      if(cacheIndex != INVALID_CACHE_INDEX)
       {
-        // 1. If preMultiplyOnLoad is MULTIPLY_ON_LOAD, then textureInfo.preMultiplyOnLoad should be true. The premultiplication result can be different.
-        // 2. If preMultiplyOnLoad is LOAD_WITHOUT_MULTIPLY, then textureInfo.preMultiplied should be false.
-        if((preMultiplyOnLoad == MultiplyOnLoad::MULTIPLY_ON_LOAD && textureInfo.preMultiplyOnLoad) || (preMultiplyOnLoad == MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY && !textureInfo.preMultiplied))
+        TextureInfo& textureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
+
+        if((url.GetUrl() == textureInfo.url.GetUrl()) &&
+           (useAtlas == textureInfo.useAtlas) &&
+           (maskTextureId == textureInfo.maskTextureId) &&
+           (cropToMask == textureInfo.cropToMask) &&
+           (size == textureInfo.desiredSize) &&
+           (isAnimatedImage == textureInfo.isAnimatedImageFormat) &&
+           ((size.GetWidth() == 0 && size.GetHeight() == 0) ||
+            (fittingMode == textureInfo.fittingMode &&
+             samplingMode == textureInfo.samplingMode)))
         {
-          // The found Texture is a match.
-          cacheIndex = i;
-          break;
+          // 1. If preMultiplyOnLoad is MULTIPLY_ON_LOAD, then textureInfo.preMultiplyOnLoad should be true. The premultiplication result can be different.
+          // 2. If preMultiplyOnLoad is LOAD_WITHOUT_MULTIPLY, then textureInfo.preMultiplied should be false.
+          if((preMultiplyOnLoad == MultiplyOnLoad::MULTIPLY_ON_LOAD && textureInfo.preMultiplyOnLoad) || (preMultiplyOnLoad == MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY && !textureInfo.preMultiplied))
+          {
+            // The found Texture is a match.
+            return cacheIndex;
+          }
         }
       }
     }
   }
 
-  return cacheIndex;
+  // Default to an invalid ID, in case we do not find a match.
+  return INVALID_CACHE_INDEX;
 }
 
 TextureCacheManager::TextureCacheIndex TextureCacheManager::AppendCache(const TextureCacheManager::TextureInfo& textureInfo)
 {
-  TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureInfoContainer.size());
+  // If we use EncodedImageBuffer, increase reference during it contains mTextureInfoContainer.
+  // This reference will be decreased when we call RemoveCache
+  if(textureInfo.url.GetProtocolType() == VisualUrl::BUFFER)
+  {
+    UseExternalResource(textureInfo.url);
+  }
+
+  TextureHash hash = textureInfo.hash;
+  TextureId   id   = textureInfo.textureId;
+
+  // Insert TextureHash container first
+  // Find exist list -or- Create new list.
+  std::vector<TextureId>& idList = mTextureHashContainer[hash];
+  // We already assume that list doesn't contain id. just emplace back
+  idList.emplace_back(id);
+
+  // Insert TextureInfo back of mTextureInfoContainer.
+  TextureCacheIndex cacheIndex = TextureCacheIndex(TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL, mTextureInfoContainer.size());
   mTextureInfoContainer.emplace_back(textureInfo);
+
+  // Add converter id --> cacheIndex
+  // NOTE : We should assume that id already generated by GenerateTextureId function.
+  mTextureIdConverter[id] = cacheIndex;
+
   return cacheIndex;
 }
 
@@ -448,17 +629,19 @@ void TextureCacheManager::RemoveCache(const TextureCacheManager::TextureId& text
 {
   TextureCacheIndex textureInfoIndex = GetCacheIndexFromId(textureId);
 
+  bool removeTextureInfo = false;
+
   if(textureInfoIndex != INVALID_CACHE_INDEX)
   {
-    TextureInfo& textureInfo(mTextureInfoContainer[textureInfoIndex]);
-    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::Remove(textureId:%d) url:%s\n  cacheIdx:%d loadState:%s reference count = %d\n", textureId, textureInfo.url.GetUrl().c_str(), textureInfoIndex, GET_LOAD_STATE_STRING(textureInfo.loadState), textureInfo.referenceCount);
+    TextureInfo& textureInfo(mTextureInfoContainer[textureInfoIndex.GetIndex()]);
+
+    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::Remove(textureId:%d) url:%s\n  cacheIdx:%d loadState:%s reference count = %d\n", textureId, textureInfo.url.GetUrl().c_str(), textureInfoIndex.GetIndex(), GET_LOAD_STATE_STRING(textureInfo.loadState), textureInfo.referenceCount);
 
     // Decrement the reference count and check if this is the last user of this Texture.
     if(--textureInfo.referenceCount <= 0)
     {
       // This is the last remove for this Texture.
       textureInfo.referenceCount = 0;
-      bool removeTextureInfo     = false;
 
       // If loaded, we can remove the TextureInfo and the Atlas (if atlased).
       if(textureInfo.loadState == LoadState::UPLOADED)
@@ -469,7 +652,7 @@ void TextureCacheManager::RemoveCache(const TextureCacheManager::TextureId& text
         }
         removeTextureInfo = true;
       }
-      else if(textureInfo.loadState == LoadState::LOADING)
+      else if(textureInfo.loadState == LoadState::LOADING || textureInfo.loadState == LoadState::MASK_APPLYING)
       {
         // We mark the textureInfo for removal.
         // Once the load has completed, this method will be called again.
@@ -487,10 +670,41 @@ void TextureCacheManager::RemoveCache(const TextureCacheManager::TextureId& text
         // If url location is BUFFER, decrease reference count of EncodedImageBuffer.
         if(textureInfo.url.IsBufferResource())
         {
-          RemoveExternalEncodedImageBuffer(textureInfo.url.GetUrl());
+          RemoveEncodedImageBuffer(textureInfo.url.GetUrl());
         }
+
         // Permanently remove the textureInfo struct.
-        mTextureInfoContainer.erase(mTextureInfoContainer.begin() + textureInfoIndex);
+
+        // Step 1. remove current textureId information in mTextureHashContainer.
+        RemoveHashId(textureInfo.hash, textureId);
+        // Step 2. make textureId is not using anymore. After this job, we can reuse textureId.
+        mTextureIdConverter.Remove(textureId);
+      }
+    }
+  }
+
+  // Post removal process to avoid mTextureInfoContainer reference problems.
+  if(removeTextureInfo)
+  {
+    // Step 3. swap last data of TextureInfoContainer, and pop_back.
+    RemoveTextureInfoByIndex(mTextureInfoContainer, textureInfoIndex);
+  }
+}
+
+void TextureCacheManager::RemoveHashId(const TextureCacheManager::TextureHash& textureHash, const TextureCacheManager::TextureId& textureId)
+{
+  auto hashIterator = mTextureHashContainer.find(textureHash);
+  if(hashIterator != mTextureHashContainer.end())
+  {
+    auto        hashIdList     = hashIterator->second;
+    const auto& hashIdIterator = std::find(hashIdList.cbegin(), hashIdList.cend(), textureId);
+    if(hashIdIterator != hashIdList.cend())
+    {
+      hashIdList.erase(hashIdIterator);
+      if(hashIdList.size() == 0)
+      {
+        // If id list in current hash is empty, remove it self in the container.
+        mTextureHashContainer.erase(hashIterator);
       }
     }
   }
index 7d941d1..dbd3e62 100644 (file)
@@ -18,7 +18,9 @@
  */
 
 // EXTERNAL INCLUDES
+#include <dali/devel-api/common/free-list.h>
 #include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
+#include <unordered_map>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/texture-manager/texture-manager-type.h>
@@ -38,11 +40,29 @@ namespace Internal
  * You can Convert TextureId into TextureCacheIndex by this class.
  *
  * Also, You can store external TextureSet or EncodedImageBuffer here.
+ *
+ * There are 3 type of CachedContainer in this manager
+ *  - mTextureInfoContainer : Cache all kind of textures that need some load/upload jobs.
+ *                            All kind of images that visual using (not vector image) will be stored here.
+ *                            This container will use TEXTURE_CACHE_INDEX_TYPE_LOCAL
+ *
+ *  - mExternalTextures : External appended TextureSet cache container.
+ *                        External TextureSet can be Something like NativeImageSource, FrameBuffer and PixelData.
+ *                        This container will use TEXTURE_CACHE_INDEX_TYPE_TEXTURE
+ *                        The textureId will be used for VisualUrl. ex) dali://1
+ *
+ *  - mEncodedImageBuffers : External appended EncodedImageBuffer cache container.
+ *                           This container will use TEXTURE_CACHE_INDEX_TYPE_BUFFER
+ *                           The bufferId will be used for VisualUrl. ex) enbuf://1
+ *                           Note that this bufferId is not equal with textureId in mTextureInfoContainer.
  */
 class TextureCacheManager
 {
 public:
   // Copy enum and types and const values that TextureCacheManager will use.
+  using TextureCacheIndexType = TextureManagerType::TextureCacheIndexType;
+  using TextureCacheIndexData = TextureManagerType::TextureCacheIndexData;
+
   using TextureId         = TextureManagerType::TextureId;
   using TextureCacheIndex = TextureManagerType::TextureCacheIndex;
   using TextureHash       = TextureManagerType::TextureHash;
@@ -81,6 +101,7 @@ public:
 
   /**
    * @brief Get the current state of a texture
+   * @note This API doesn't consider 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.
@@ -89,6 +110,7 @@ public:
 
   /**
    * @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.
@@ -111,17 +133,17 @@ public:
 
   /**
    * @brief Get the encoded image buffer
-   * @param[in] textureId The textureId to look up
-   * @return the encoded image buffer, or an empty handle if textureId is not valid
+   * @param[in] bufferId The bufferId to look up
+   * @return the encoded image buffer, or an empty handle if bufferId is not valid
    */
-  EncodedImageBuffer GetEncodedImageBuffer(const TextureCacheManager::TextureId& textureId);
+  EncodedImageBuffer GetEncodedImageBuffer(const TextureCacheManager::TextureId& bufferId);
 
   /**
    * @brief Get the encoded image buffer by VisualUrl
    * @param[in] url The url to look up
    * @return the encoded image buffer, or an empty handle if url is not buffer resource or buffer is not valid
    */
-  EncodedImageBuffer GetEncodedImageBuffer(const std::string& url);
+  EncodedImageBuffer GetEncodedImageBuffer(const VisualUrl& url);
 
   /**
    * Adds an external texture to the texture manager
@@ -131,28 +153,28 @@ public:
   std::string AddExternalTexture(const TextureSet& texture);
 
   /**
-   * Adds an external encoded image buffer to the texture manager
+   * Adds an encoded image buffer to the texture manager
    * @param[in] encodedImageBuffer The image buffer to add
    * @return string containing the URL for the texture
    */
-  std::string AddExternalEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer);
+  std::string AddEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer);
 
   /**
    * Removes an external texture from texture manager
    * @param[in] url The string containing the texture to remove
    * @return handle to the texture
    */
-  TextureSet RemoveExternalTexture(const std::string& url);
+  TextureSet RemoveExternalTexture(const VisualUrl& url);
 
   /**
    * Removes an external encoded image buffer from texture manager
    * @param[in] url The string containing the encoded image buffer to remove
    * @return handle to the encoded image buffer
    */
-  EncodedImageBuffer RemoveExternalEncodedImageBuffer(const std::string& url);
+  EncodedImageBuffer RemoveEncodedImageBuffer(const VisualUrl& url);
 
   /**
-   * @brief Notify that external textures or external encoded image buffers are used.
+   * @brief Notify that external textures or encoded image buffers are used.
    * @param[in] url The URL of the texture to use.
    */
   void UseExternalResource(const VisualUrl& url);
@@ -161,10 +183,11 @@ public:
   // To Generate / Get / Remove TextureId.
 
   /**
-   * @brief Generates a new, unique TextureId
-   * @return A unique TextureId
+   * @brief Generates a new valid TextureId.
+   * @param[in] textureCacheIndex the index of the cache container. If we don't setup this value, default is INVALID_CACHE_INDEX
+   * @return A TextureId
    */
-  TextureCacheManager::TextureId GenerateUniqueTextureId();
+  TextureCacheManager::TextureId GenerateTextureId(const TextureCacheIndex& textureCacheIndex = INVALID_CACHE_INDEX);
 
   /**
    * @brief Used to lookup an index into the TextureInfoContainer from a TextureId
@@ -184,15 +207,17 @@ public:
    * @param[in] samplingMode     The SamplingMode to use
    * @param[in] useAtlas         True if atlased
    * @param[in] maskTextureId    The masking texture id (or INVALID_TEXTURE_ID)
+   * @param[in] cropToMask       True if crop to mask
    * @return                     A hash of the provided data for caching.
    */
   TextureCacheManager::TextureHash GenerateHash(
-    const std::string&                    url,
+    const VisualUrl&                      url,
     const Dali::ImageDimensions&          size,
     const Dali::FittingMode::Type&        fittingMode,
     const Dali::SamplingMode::Type&       samplingMode,
     const TextureCacheManager::UseAtlas&  useAtlas,
-    const TextureCacheManager::TextureId& maskTextureId);
+    const TextureCacheManager::TextureId& maskTextureId,
+    const bool&                           cropToMask);
 
   /**
    * @brief Looks up a cached texture by its hash.
@@ -204,24 +229,27 @@ public:
    * @param[in] samplingMode      The SamplingMode to use
    * @param[in] useAtlas          True if atlased
    * @param[in] maskTextureId     Optional texture ID to use to mask this image
-   * @param[in] preMultiplyOnLoad If the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha.
+   * @param[in] preMultiplyOnLoad if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha.
    * @param[in] isAnimatedImage   True if the texture is from animated image.
-   * @return                      A TextureCacheId of a cached Texture if found. Or INVALID_CACHE_INDEX if not found.
+   * @param[in] cropToMask        True if crop to mask
+   * @return                      A TextureCacheIndex of a cached Texture if found. Or INVALID_CACHE_INDEX if not found.
    */
   TextureCacheManager::TextureCacheIndex FindCachedTexture(
     const TextureCacheManager::TextureHash&    hash,
-    const std::string&                         url,
+    const VisualUrl&                           url,
     const Dali::ImageDimensions&               size,
     const Dali::FittingMode::Type&             fittingMode,
     const Dali::SamplingMode::Type&            samplingMode,
     const TextureCacheManager::UseAtlas&       useAtlas,
     const TextureCacheManager::TextureId&      maskTextureId,
+    const bool&                                cropToMask,
     const TextureCacheManager::MultiplyOnLoad& preMultiplyOnLoad,
-    bool                                       isAnimatedImage);
+    const bool&                                isAnimatedImage);
 
   /**
    * @brief Append a Texture to the TextureCacheManager.
    * @note This API doesn't check duplication of TextureId.
+   * @note This API doesn't consider external & encodedimagebuffer.
    *
    * @param[in] textureInfo TextureInfo that want to cache in container.
    * @return Index of newly appended texture info.
@@ -230,6 +258,7 @@ public:
 
   /**
    * @brief Remove a Texture from the TextureCacheManager.
+   * @note This API doesn't consider external & encodedimagebuffer.
    *
    * Textures are cached and therefore only the removal of the last
    * occurrence of a Texture will cause its removal internally.
@@ -247,7 +276,7 @@ public:
    */
   inline TextureCacheManager::TextureInfo& operator[](const TextureCacheManager::TextureCacheIndex& textureCacheIndex) noexcept
   {
-    return mTextureInfoContainer[textureCacheIndex];
+    return mTextureInfoContainer[textureCacheIndex.GetIndex()];
   }
 
   /**
@@ -263,6 +292,9 @@ public:
 private:
   // Private defined structs.
 
+  /**
+   * @brief This struct is used to manage the life-cycle of ExternalTexture url.
+   */
   struct ExternalTextureInfo
   {
     ExternalTextureInfo(const TextureCacheManager::TextureId& textureId,
@@ -277,23 +309,77 @@ private:
     std::int16_t                   referenceCount;
   };
 
-  struct EncodedBufferTextureInfo
+  /**
+   * @brief This struct is used to manage the life-cycle of EncodedImageBuffer url.
+   */
+  struct EncodedImageBufferInfo
   {
-    EncodedBufferTextureInfo(const TextureCacheManager::TextureId& textureId,
-                             const EncodedImageBuffer&             encodedImageBuffer)
-    : textureId(textureId),
+    EncodedImageBufferInfo(const TextureCacheManager::TextureId&   bufferId,
+                           const TextureCacheManager::TextureHash& bufferHash,
+                           const EncodedImageBuffer&               encodedImageBuffer)
+    : bufferId(bufferId),
+      bufferHash(bufferHash),
       encodedImageBuffer(encodedImageBuffer),
       referenceCount(1u)
     {
     }
-    TextureCacheManager::TextureId textureId;
-    EncodedImageBuffer             encodedImageBuffer;
-    std::int16_t                   referenceCount;
+    TextureCacheManager::TextureId   bufferId;
+    TextureCacheManager::TextureHash bufferHash;
+    EncodedImageBuffer               encodedImageBuffer;
+    std::int16_t                     referenceCount;
   };
 
-  typedef std::vector<TextureCacheManager::TextureInfo>              TextureInfoContainerType;              ///< The container type used to manage the life-cycle and caching of Textures
-  typedef std::vector<TextureCacheManager::ExternalTextureInfo>      ExternalTextureInfoContainerType;      ///< The container type used to manage the life-cycle and caching of Textures
-  typedef std::vector<TextureCacheManager::EncodedBufferTextureInfo> EncodedBufferTextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of Textures
+  typedef Dali::FreeList TextureIdConverterType; ///< The converter type from TextureId to index of TextureInfoContainer.
+
+  typedef std::unordered_map<TextureCacheManager::TextureHash, std::vector<TextureCacheManager::TextureId>> TextureHashContainerType;            ///< The container type used to fast-find the TextureId by TextureHash.
+  typedef std::vector<TextureCacheManager::TextureInfo>                                                     TextureInfoContainerType;            ///< The container type used to manage the life-cycle and caching of Textures
+  typedef std::vector<TextureCacheManager::ExternalTextureInfo>                                             ExternalTextureInfoContainerType;    ///< The container type used to manage the life-cycle and caching of ExternalTexture url
+  typedef std::vector<TextureCacheManager::EncodedImageBufferInfo>                                          EncodedImageBufferInfoContainerType; ///< The container type used to manage the life-cycle and caching of EncodedImageBuffer url
+
+private:
+  // Private API: only used internally
+
+  /**
+   * @brief Used to lookup an index into the ExternalTextureInfoContainer from a textureId
+   * @param[in] textureId The TextureId to look up
+   * @return              The cache index
+   */
+  TextureCacheManager::TextureCacheIndex GetCacheIndexFromExternalTextureId(const TextureCacheManager::TextureId& textureId);
+
+  /**
+   * @brief Used to lookup an index into the EncodedImageBufferInfoContainer from a bufferId
+   * @param[in] bufferId The bufferId to look up
+   * @return             The cache index
+   */
+  TextureCacheManager::TextureCacheIndex GetCacheIndexFromEncodedImageBufferId(const TextureCacheManager::TextureId& bufferId);
+
+  /**
+   * @brief Looks up a cached encoded image buffer cached by its hash.
+   * If found, the given parameters are used to check there is no hash-collision.
+   * @param[in] hash               The hash to look up
+   * @param[in] encodedImageBuffer The image buffer to load
+   * @return                       A TextureCacheIndex of a cached Texture if found. Or INVALID_CACHE_INDEX if not found.
+   */
+  TextureCacheManager::TextureCacheIndex FindCachedEncodedImageBuffer(const TextureCacheManager::TextureHash& hash, const EncodedImageBuffer& encodedImageBuffer);
+
+  /**
+   * @brief Remove id in HashContainer.
+   * @param[in] hash The hash of the texture/buffer to be delete
+   * @param[in] id   The texture/buffer id to be deleted.
+   */
+  void RemoveHashId(const TextureCacheManager::TextureHash& hash, const TextureCacheManager::TextureId& id);
+
+  /**
+   * @brief Remove data from container by the TextureCacheIndex.
+   * It also valiate the TextureIdConverter internally.
+   * We will assume that only valid TextureCacheIndex will come.
+   *
+   * @tparam ContainerType The type of container. It will automatically defined
+   * @param[in] cacheContainer The container that will remove texture info.
+   * @param[in] removeContainerIndex The index of texture info that will remove.
+   */
+  template<class ContainerType>
+  void RemoveTextureInfoByIndex(ContainerType& cacheContainer, const TextureCacheManager::TextureCacheIndex& removeContainerIndex);
 
 private:
   /**
@@ -306,11 +392,13 @@ private:
    */
   TextureCacheManager& operator=(const TextureCacheManager& rhs) = delete;
 
-private:                                                          // Member Variables:
-  TextureInfoContainerType              mTextureInfoContainer{};  ///< Used to manage the life-cycle and caching of Textures
-  ExternalTextureInfoContainerType      mExternalTextures{};      ///< Externally provided textures
-  EncodedBufferTextureInfoContainerType mEncodedBufferTextures{}; ///< Externally encoded buffer textures
-  TextureCacheManager::TextureId        mCurrentTextureId;        ///< The current value used for the unique Texture Id generation
+private:                                            // Member Variables:
+  TextureIdConverterType   mTextureIdConverter{};   ///< Convert TextureId into various container's index.
+  TextureHashContainerType mTextureHashContainer{}; ///< Used to manage the life-cycle and caching of Textures + EncodedImageBuffer by TextureHash
+
+  TextureInfoContainerType            mTextureInfoContainer{}; ///< Used to manage the life-cycle and caching of Textures
+  ExternalTextureInfoContainerType    mExternalTextures{};     ///< Externally provided textures
+  EncodedImageBufferInfoContainerType mEncodedImageBuffers{};  ///< Externally encoded image buffer
 };
 
 } // namespace Internal
index ff81b22..390bb20 100644 (file)
@@ -123,6 +123,7 @@ TextureManager::TextureManager()
   mAsyncRemoteLoaders(GetNumberOfRemoteLoaderThreads(), [&]() { return TextureAsyncLoadingHelper(*this); }),
   mLifecycleObservers(),
   mLoadQueue(),
+  mRemoveQueue(),
   mQueueLoadFlag(false)
 {
   // Initialize the AddOn
@@ -211,7 +212,7 @@ Devel::PixelBuffer TextureManager::LoadPixelBuffer(
     {
       if(url.IsBufferResource())
       {
-        const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(url.GetUrl());
+        const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(url);
         if(encodedImageBuffer)
         {
           pixelBuffer = LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), desiredSize, fittingMode, samplingMode, orientationCorrection);
@@ -468,10 +469,10 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
   TextureCacheIndex cacheIndex  = INVALID_CACHE_INDEX;
   if(storageType != StorageType::RETURN_PIXEL_BUFFER && useCache)
   {
-    textureHash = mTextureCacheManager.GenerateHash(url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId);
+    textureHash = mTextureCacheManager.GenerateHash(url, desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, cropToMask);
 
     // Look up the texture by hash. Note: The extra parameters are used in case of a hash collision.
-    cacheIndex = mTextureCacheManager.FindCachedTexture(textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, preMultiplyOnLoad, (animatedImageLoading) ? true : false);
+    cacheIndex = mTextureCacheManager.FindCachedTexture(textureHash, url, desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, cropToMask, preMultiplyOnLoad, (animatedImageLoading) ? true : false);
   }
 
   TextureManager::TextureId textureId = INVALID_TEXTURE_ID;
@@ -489,41 +490,19 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
     // 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 observer=%p ) Using cached texture id@%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId);
+    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture id@%d, textureId=%d premultiplied=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId, mTextureCacheManager[cacheIndex].preMultiplied ? 1 : 0);
   }
 
   if(textureId == INVALID_TEXTURE_ID) // There was no caching, or caching not required
   {
-    if(VisualUrl::BUFFER == url.GetProtocolType())
-    {
-      std::string location = url.GetLocation();
-      if(location.size() > 0u)
-      {
-        TextureId                 targetId           = std::stoi(location);
-        const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(targetId);
-        if(encodedImageBuffer)
-        {
-          textureId = targetId;
-
-          // Increase EncodedImageBuffer reference during it contains mTextureInfoContainer.
-          // TODO! We should change action when reload policy is FORCE.
-          // Eunki Hong will fix it after refactoring patch merged.
-          mTextureCacheManager.UseExternalResource(url.GetUrl());
-        }
-      }
-    }
-
-    if(textureId == INVALID_TEXTURE_ID)
-    {
-      textureId = mTextureCacheManager.GenerateUniqueTextureId();
-    }
+    textureId = mTextureCacheManager.GenerateTextureId();
 
     bool preMultiply = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
 
     // Cache new texutre, and get cacheIndex.
     cacheIndex = mTextureCacheManager.AppendCache(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex));
 
-    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId);
+    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId);
   }
 
   // The below code path is common whether we are using the cache or not.
@@ -544,7 +523,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
      TextureManager::LoadState::MASK_APPLIED != textureInfo.loadState &&
      TextureManager::LoadState::CANCELLED != textureInfo.loadState)
   {
-    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "TextureManager::RequestLoad( url=%s observer=%p ) ForcedReload cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId);
+    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "TextureManager::RequestLoad( url=%s observer=%p ) ForcedReload cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId);
 
     textureInfo.loadState = TextureManager::LoadState::NOT_STARTED;
   }
@@ -651,19 +630,30 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
 
 void TextureManager::Remove(const TextureManager::TextureId& textureId, TextureUploadObserver* observer)
 {
-  // Remove textureId in CacheManager.
-  mTextureCacheManager.RemoveCache(textureId);
-
-  if(observer)
+  if(textureId != INVALID_TEXTURE_ID)
   {
-    // Remove element from the LoadQueue
-    for(auto&& element : mLoadQueue)
+    if(mQueueLoadFlag)
+    {
+      // Remove textureId after NotifyObserver finished
+      mRemoveQueue.PushBack(textureId);
+    }
+    else
     {
-      if(element.mObserver == observer)
+      // Remove textureId in CacheManager.
+      mTextureCacheManager.RemoveCache(textureId);
+    }
+
+    if(observer)
+    {
+      // Remove element from the LoadQueue
+      for(auto&& element : mLoadQueue)
       {
-        // Do not erase the item. We will clear it later in ProcessQueuedTextures().
-        element.mObserver = nullptr;
-        break;
+        if(element.mObserver == observer)
+        {
+          // Do not erase the item. We will clear it later in ProcessLoadQueue().
+          element.mObserver = nullptr;
+          break;
+        }
       }
     }
   }
@@ -679,7 +669,7 @@ Devel::PixelBuffer TextureManager::LoadImageSynchronously(
   Devel::PixelBuffer pixelBuffer;
   if(url.IsBufferResource())
   {
-    const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(url.GetUrl());
+    const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(url);
     if(encodedImageBuffer)
     {
       pixelBuffer = LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), desiredSize, fittingMode, samplingMode, orientationCorrection);
@@ -789,7 +779,7 @@ void TextureManager::LoadTexture(TextureManager::TextureInfo& textureInfo, Textu
   ObserveTexture(textureInfo, observer);
 }
 
-void TextureManager::ProcessQueuedTextures()
+void TextureManager::ProcessLoadQueue()
 {
   for(auto&& element : mLoadQueue)
   {
@@ -815,6 +805,15 @@ void TextureManager::ProcessQueuedTextures()
   mLoadQueue.Clear();
 }
 
+void TextureManager::ProcessRemoveQueue()
+{
+  for(const auto& textureId : mRemoveQueue)
+  {
+    mTextureCacheManager.RemoveCache(textureId);
+  }
+  mRemoveQueue.Clear();
+}
+
 void TextureManager::ObserveTexture(TextureManager::TextureInfo& textureInfo,
                                     TextureUploadObserver*       observer)
 {
@@ -829,13 +828,13 @@ void TextureManager::ObserveTexture(TextureManager::TextureInfo& textureInfo,
 
 void TextureManager::AsyncLoadComplete(const TextureManager::TextureId& textureId, Devel::PixelBuffer pixelBuffer)
 {
-  DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::AsyncLoadComplete( textureId:%d )\n", textureId);
   TextureCacheIndex cacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureId);
+  DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::AsyncLoadComplete( textureId:%d CacheIndex:%d )\n", textureId, cacheIndex.GetIndex());
   if(cacheIndex != INVALID_CACHE_INDEX)
   {
     TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]);
 
-    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "  textureId:%d Url:%s CacheIndex:%d LoadState: %s\n", textureInfo.textureId, textureInfo.url.GetUrl().c_str(), cacheIndex, GET_LOAD_STATE_STRING(textureInfo.loadState));
+    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "  textureId:%d Url:%s CacheIndex:%d LoadState: %s\n", textureInfo.textureId, textureInfo.url.GetUrl().c_str(), cacheIndex.GetIndex(), GET_LOAD_STATE_STRING(textureInfo.loadState));
 
     if(textureInfo.loadState != LoadState::CANCELLED)
     {
@@ -939,11 +938,12 @@ void TextureManager::CheckForWaitingTexture(TextureManager::TextureInfo& maskTex
 {
   // Search the cache, checking if any texture has this texture id as a
   // maskTextureId:
-  const TextureCacheIndex size = static_cast<TextureCacheIndex>(mTextureCacheManager.size());
+  const std::size_t size = mTextureCacheManager.size();
 
   const bool maskLoadSuccess = maskTextureInfo.loadState == LoadState::LOAD_FINISHED ? true : false;
 
-  for(TextureCacheIndex cacheIndex = 0; cacheIndex < size; ++cacheIndex)
+  // TODO : Refactorize here to not iterate whole cached image.
+  for(TextureCacheIndex cacheIndex = TextureCacheIndex(TextureManagerType::TEXTURE_CACHE_INDEX_TYPE_LOCAL, 0u); cacheIndex.GetIndex() < size; ++cacheIndex.detailValue.index)
   {
     if(mTextureCacheManager[cacheIndex].maskTextureId == maskTextureInfo.textureId &&
        mTextureCacheManager[cacheIndex].loadState == LoadState::WAITING_FOR_MASK)
@@ -1052,7 +1052,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() textureId:%d url:%s loadState:%s\n", textureId, textureInfo.url.GetUrl().c_str(), GET_LOAD_STATE_STRING(textureInfo.loadState));
+    DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::NotifyObservers() textureId:%d url:%s loadState:%s\n", textureId, info->url.GetUrl().c_str(), GET_LOAD_STATE_STRING(info->loadState));
 
     // It is possible for the observer to be deleted.
     // Disconnect and remove the observer first.
@@ -1072,7 +1072,8 @@ void TextureManager::NotifyObservers(TextureManager::TextureInfo& textureInfo, c
   }
 
   mQueueLoadFlag = false;
-  ProcessQueuedTextures();
+  ProcessLoadQueue();
+  ProcessRemoveQueue();
 
   if(info->storageType == StorageType::RETURN_PIXEL_BUFFER && info->observerList.Count() == 0)
   {
@@ -1082,10 +1083,10 @@ void TextureManager::NotifyObservers(TextureManager::TextureInfo& textureInfo, c
 
 void TextureManager::ObserverDestroyed(TextureUploadObserver* observer)
 {
-  const TextureCacheIndex count = static_cast<TextureCacheIndex>(mTextureCacheManager.size());
-  for(TextureCacheIndex i = 0; i < count; ++i)
+  const std::size_t size = mTextureCacheManager.size();
+  for(TextureCacheIndex cacheIndex = TextureCacheIndex(TextureManagerType::TEXTURE_CACHE_INDEX_TYPE_LOCAL, 0u); cacheIndex.GetIndex() < size; ++cacheIndex.detailValue.index)
   {
-    TextureInfo& textureInfo(mTextureCacheManager[i]);
+    TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]);
     for(TextureInfo::ObserverListType::Iterator j = textureInfo.observerList.Begin();
         j != textureInfo.observerList.End();)
     {
index 01f62ee..ee1f065 100644 (file)
@@ -283,11 +283,11 @@ public:
   }
 
   /**
-   * @copydoc TextureCacheManager::RemoveExternalEncodedImageBuffer
+   * @copydoc TextureCacheManager::RemoveEncodedImageBuffer
    */
-  inline EncodedImageBuffer RemoveExternalEncodedImageBuffer(const std::string& url)
+  inline EncodedImageBuffer RemoveEncodedImageBuffer(const std::string& url)
   {
-    return mTextureCacheManager.RemoveExternalEncodedImageBuffer(url);
+    return mTextureCacheManager.RemoveEncodedImageBuffer(url);
   }
 
   /**
@@ -315,11 +315,11 @@ public:
   }
 
   /**
-   * @copydoc TextureCacheManager::AddExternalEncodedImageBuffer
+   * @copydoc TextureCacheManager::AddEncodedImageBuffer
    */
-  inline std::string AddExternalEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer)
+  inline std::string AddEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer)
   {
-    return mTextureCacheManager.AddExternalEncodedImageBuffer(encodedImageBuffer);
+    return mTextureCacheManager.AddEncodedImageBuffer(encodedImageBuffer);
   }
 
 public: // Load Request API
@@ -536,7 +536,12 @@ private:
   /**
    * @brief Initiate load of textures queued whilst NotifyObservers invoking callbacks.
    */
-  void ProcessQueuedTextures();
+  void ProcessLoadQueue();
+
+  /**
+   * @brief Initiate remove of texture queued whilst NotifyObservers invoking callbacks.
+   */
+  void ProcessRemoveQueue();
 
   /**
    * Add the observer to the observer list
@@ -624,9 +629,10 @@ private:                                    // Member Variables:
   RoundRobinContainerView<TextureAsyncLoadingHelper> mAsyncLocalLoaders;  ///< The Asynchronous image loaders used to provide all local async loads
   RoundRobinContainerView<TextureAsyncLoadingHelper> mAsyncRemoteLoaders; ///< The Asynchronous image loaders used to provide all remote async loads
 
-  Dali::Vector<LifecycleObserver*> mLifecycleObservers; ///< Lifecycle observers of texture manager
-  Dali::Vector<LoadQueueElement>   mLoadQueue;          ///< Queue of textures to load after NotifyObservers
-  bool                             mQueueLoadFlag;      ///< Flag that causes Load Textures to be queued.
+  Dali::Vector<LifecycleObserver*>        mLifecycleObservers; ///< Lifecycle observers of texture manager
+  Dali::Vector<LoadQueueElement>          mLoadQueue;          ///< Queue of textures to load after NotifyObservers
+  Dali::Vector<TextureManager::TextureId> mRemoveQueue;        ///< Queue of textures to remove after NotifyObservers
+  bool                                    mQueueLoadFlag;      ///< Flag that causes Load Textures to be queued.
 };
 
 } // namespace Internal
index 514e544..366e7cb 100644 (file)
@@ -38,18 +38,123 @@ namespace Internal
  */
 namespace TextureManagerType
 {
+// Enum!
+
+enum TextureCacheIndexType
+{
+  TEXTURE_CACHE_INDEX_FREE_LIST  = 0, ///< Only for FreeList. We should not use this for TextureCacheIndex.
+  TEXTURE_CACHE_INDEX_TYPE_LOCAL = 1,
+  TEXTURE_CACHE_INDEX_TYPE_TEXTURE,
+  TEXTURE_CACHE_INDEX_TYPE_BUFFER,
+  TEXTURE_CACHE_INDEX_TYPE_MASKING, ///< Not implemented yet.
+  TEXTURE_CACHE_INDEX_TYPE_MAX = 7, ///< Maximum number of cache type we can use.
+};
+
+// Union!
+
+/**
+ * @brief standard union type of texture index.
+ * Due to the FreeList can only use for uint32_t and we need to seperate
+ * each index per container type, we can only hold maximum 2^28 textures
+ * at the same time.
+ *      0 ~   2^28 - 1 : index of FreeList. TextureCacheManager will not use it.
+ *   2^28 ~ 2*2^28 - 1 : index of mTextureInfoContainer, the main texture container.
+ * 2*2^28 ~ 3*2^28 - 1 : index of mExternalTextures.
+ * 3*2^28 ~ 4*2^28 - 1 : index of mEncodedBufferTextures.
+ */
+union TextureCacheIndexData
+{
+  TextureCacheIndexData() = default;
+  constexpr TextureCacheIndexData(const std::uint32_t& index)
+  : indexValue(index)
+  {
+  }
+  constexpr explicit TextureCacheIndexData(const std::int32_t& index)
+  : indexValue(static_cast<std::uint32_t>(index))
+  {
+  }
+  constexpr TextureCacheIndexData(const TextureCacheIndexType& type, const std::uint32_t& index)
+  : detailValue{index, type}
+  {
+  }
+  constexpr TextureCacheIndexData(const TextureCacheIndexData& indexData)
+  : indexValue(indexData.indexValue)
+  {
+  }
+  constexpr TextureCacheIndexData(TextureCacheIndexData&& indexData)
+  : indexValue(indexData.indexValue)
+  {
+  }
+
+  TextureCacheIndexData& operator=(const std::uint32_t& index)
+  {
+    indexValue = index;
+    return *this;
+  }
+  TextureCacheIndexData& operator=(const TextureCacheIndexData& rhs)
+  {
+    indexValue = rhs.indexValue;
+    return *this;
+  }
+  TextureCacheIndexData& operator=(TextureCacheIndexData&& rhs)
+  {
+    indexValue = rhs.indexValue;
+    return *this;
+  }
+
+  constexpr operator std::uint32_t() const
+  {
+    return indexValue;
+  }
+  constexpr operator std::uint32_t()
+  {
+    return indexValue;
+  }
+  constexpr explicit operator std::int32_t() const
+  {
+    return static_cast<std::int32_t>(indexValue);
+  }
+  constexpr explicit operator std::int32_t()
+  {
+    return static_cast<std::int32_t>(indexValue);
+  }
+
+  // Return detailValue.index. - the real index of datailValue.type container
+  constexpr inline std::uint32_t GetIndex() const
+  {
+    return detailValue.index;
+  }
+
+  inline constexpr bool operator==(const TextureCacheIndexData& rhs)
+  {
+    return indexValue == rhs.indexValue;
+  }
+  inline constexpr bool operator<(const TextureCacheIndexData& rhs)
+  {
+    return indexValue < rhs.indexValue;
+  }
+
+  // Data area
+  std::uint32_t indexValue;
+  struct
+  {
+    unsigned int          index : 28;
+    TextureCacheIndexType type : 4;
+  } detailValue;
+};
+
 // Typedef:
 
-typedef std::int32_t TextureId;         ///< The TextureId type. This is used as a handle to refer to a particular Texture.
-typedef std::int32_t TextureCacheIndex; ///< The TextureCacheIndex type. This is used as a handles to refer to a particular Texture in TextureCacheManager.
-                                        ///  Note : For the same Texture, TextureId will not be changed. But TextureCacheIndex can be chaged when TextureCacheManager
-                                        ///  Internal container informations changed by Append or Remove.
-typedef std::size_t TextureHash;        ///< The type used to store the hash used for Texture caching.
+typedef std::int32_t          TextureId;         ///< The TextureId type. This is used as a handle to refer to a particular Texture.
+typedef TextureCacheIndexData TextureCacheIndex; ///< The TextureCacheIndex type. This is used as a handles to refer to a particular Texture in TextureCacheManager.
+                                                 ///  Note : For the same Texture, TextureId will not be changed. But TextureCacheIndex can be chaged when TextureCacheManager
+                                                 ///  Internal container informations changed by Append or Remove.
+typedef std::size_t TextureHash;                 ///< The type used to store the hash used for Texture caching.
 
 // Constant values:
 
 static constexpr TextureId         INVALID_TEXTURE_ID  = -1; ///< Used to represent a null TextureId or error
-static constexpr TextureCacheIndex INVALID_CACHE_INDEX = -1; ///< Used to represent a null TextureCacheIndex or error
+static constexpr TextureCacheIndex INVALID_CACHE_INDEX = 0;  ///< Used to represent a null TextureCacheIndex or error
 
 // Enum classes:
 
index d5dcdaa..be73cca 100644 (file)
@@ -201,7 +201,7 @@ void AnimatedImageVisual::CreateImageCache()
 }
 
 AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory)
-: Visual::Base(factoryCache, Visual::FittingMode::FIT_KEEP_ASPECT_RATIO, Toolkit::Visual::ANIMATED_IMAGE),
+: Visual::Base(factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::ANIMATED_IMAGE),
   mFrameDelayTimer(),
   mPlacementActor(),
   mImageVisualShaderFactory(shaderFactory),
index e971be6..a2e9096 100644 (file)
@@ -202,7 +202,7 @@ ImageVisual::~ImageVisual()
       else if(mImageUrl.IsBufferResource())
       {
         TextureManager& textureManager = mFactoryCache.GetTextureManager();
-        textureManager.RemoveExternalEncodedImageBuffer(mImageUrl.GetUrl());
+        textureManager.RemoveEncodedImageBuffer(mImageUrl.GetUrl());
       }
     }
 
index 0ad5778..af3b04c 100644 (file)
@@ -105,6 +105,7 @@ VisualUrl::Type ResolveType(const std::string& url)
 {
   // if only one char in string, can only be regular image
   const std::size_t count = url.size();
+  VisualUrl::Type  returnType = VisualUrl::REGULAR_IMAGE;
   if(count > 0)
   {
     // parsing from the end for better chance of early outs
@@ -147,18 +148,18 @@ VisualUrl::Type ResolveType(const std::string& url)
       }
       if((offsetFromEnd < sizeof(GIF)) && (currentChar == GIF[offsetFromEnd]))
       {
-        // early out if GIF as can't be used in N patch for now
+        //find type, but need to be check used in N patch
         if(++gifScore == sizeof(GIF))
         {
-          return VisualUrl::GIF;
+          returnType = VisualUrl::GIF;
         }
       }
       if((offsetFromEnd < sizeof(WEBP)) && (currentChar == WEBP[offsetFromEnd]))
       {
-        // early out if WEBP as can't be used in N patch for now
         if(++webpScore == sizeof(WEBP))
         {
-          return VisualUrl::WEBP;
+          //find type, but need to be check used in N patch
+          returnType = VisualUrl::WEBP;
         }
       }
       if((offsetFromEnd < sizeof(JSON)) && (currentChar == JSON[offsetFromEnd]))
@@ -188,7 +189,7 @@ VisualUrl::Type ResolveType(const std::string& url)
           else
           {
             // early out, not a valid N/9-patch URL
-            return VisualUrl::REGULAR_IMAGE;
+            return returnType;
           }
           break;
         }
@@ -201,7 +202,7 @@ VisualUrl::Type ResolveType(const std::string& url)
           else
           {
             // early out, not a valid N/9-patch URL
-            return VisualUrl::REGULAR_IMAGE;
+            return returnType;
           }
           break;
         }
@@ -209,7 +210,7 @@ VisualUrl::Type ResolveType(const std::string& url)
     }
   }
   // if we got here it is a regular image
-  return VisualUrl::REGULAR_IMAGE;
+  return returnType;
 }
 
 } // namespace
index e704530..a67d9ee 100644 (file)
@@ -29,7 +29,7 @@ namespace Toolkit
 {
 const unsigned int TOOLKIT_MAJOR_VERSION = 2;
 const unsigned int TOOLKIT_MINOR_VERSION = 1;
-const unsigned int TOOLKIT_MICRO_VERSION = 19;
+const unsigned int TOOLKIT_MICRO_VERSION = 20;
 const char* const  TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index c2a9846..1a5ec39 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali2-toolkit
 Summary:    Dali 3D engine Toolkit
-Version:    2.1.19
+Version:    2.1.20
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT