[Tizen] Support to use NPatchImage in brokenImage 44/263744/9
authorSunghyun Kim <scholb.kim@samsung.com>
Tue, 29 Jun 2021 07:38:09 +0000 (16:38 +0900)
committertscholb <scholb.kim@samsung.com>
Thu, 16 Sep 2021 06:37:38 +0000 (15:37 +0900)
Support to use NpatchImage in broken Image.
Application can use custom broken image from this patch.
when they set 3 type of broken image(small,normal,large),
dali show the proper broken image considering size.

Change-Id: I7e2be85d4715d07356fd2782be2d011931fde5c2

14 files changed:
dali-toolkit/devel-api/styling/style-manager-devel.cpp
dali-toolkit/devel-api/styling/style-manager-devel.h
dali-toolkit/internal/styling/style-manager-impl.cpp
dali-toolkit/internal/styling/style-manager-impl.h
dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp
dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.cpp
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/npatch-loader.cpp
dali-toolkit/internal/visuals/npatch/npatch-visual.cpp
dali-toolkit/internal/visuals/svg/svg-visual.cpp
dali-toolkit/internal/visuals/visual-factory-cache.cpp
dali-toolkit/internal/visuals/visual-factory-cache.h
dali-toolkit/internal/visuals/visual-factory-impl.cpp
dali-toolkit/internal/visuals/visual-factory-impl.h

index 29f0e8b..94b3ecc 100644 (file)
@@ -30,6 +30,16 @@ const Property::Map GetConfigurations(StyleManager styleManager)
   return GetImpl(styleManager).GetConfigurations();
 }
 
+void SetBrokenImageUrl(StyleManager styleManager, DevelStyleManager::BrokenImageType brokenImageType, const std::string& brokenImageUrl)
+{
+  return GetImpl(styleManager).SetBrokenImageUrl(Internal::StyleManager::BrokenImageType(brokenImageType), brokenImageUrl);
+}
+
+std::string GetBrokenImageUrl(StyleManager styleManager, DevelStyleManager::BrokenImageType brokenImageType)
+{
+  return GetImpl(styleManager).GetBrokenImageUrl(Internal::StyleManager::BrokenImageType(brokenImageType));
+}
+
 } // namespace DevelStyleManager
 
 } // namespace Toolkit
index efcff7d..44162fd 100644 (file)
@@ -28,6 +28,16 @@ namespace Toolkit
 namespace DevelStyleManager
 {
 /**
+ * @brief The Type of BrokenImage
+ */
+enum BrokenImageType
+{
+  SMALL,
+  NORMAL,
+  LARGE
+};
+
+/**
  * @brief Gets all currently defined configurations.
  *
  * @pre The Builder has been initialized.
@@ -36,6 +46,21 @@ namespace DevelStyleManager
 **/
 DALI_TOOLKIT_API const Property::Map GetConfigurations(StyleManager styleManager);
 
+/**
+   * @brief Sets an image to be used when a visual has failed to correctly render
+   * @param[in] styleManager The instance of StyleManager
+   * @param[in] brokenImageType The type of broken image
+   * @param[in] brokenImageUrl The broken image url
+   */
+DALI_TOOLKIT_API void SetBrokenImageUrl(StyleManager styleManager, DevelStyleManager::BrokenImageType brokenImageType, const std::string& brokenImageUrl);
+
+/**
+   * @brief Gets an image to be used when a visual has failed to correctly render
+   * @param[in] styleManager The instance of StyleManager
+   * @param[in] brokenImageType BrokenImage type
+   */
+DALI_TOOLKIT_API std::string GetBrokenImageUrl(StyleManager styleManager, DevelStyleManager::BrokenImageType brokenImageType);
+
 } // namespace DevelStyleManager
 
 } // namespace Toolkit
index 0968081..13d5f7d 100644 (file)
@@ -45,6 +45,8 @@ const char* APPLICATION_RESOURCE_PATH_KEY = "APPLICATION_RESOURCE_PATH";
 
 const char* DEFAULT_TOOLKIT_PACKAGE_PATH = "/toolkit/";
 
+static constexpr int32_t COUNT_BROKEN_IMAGE_MAX = 3;
+
 #if defined(DEBUG_ENABLED)
 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_STYLE");
 #endif
@@ -125,6 +127,9 @@ StyleManager::StyleManager()
 
   // Sound & haptic style
   mFeedbackStyle = new FeedbackStyle();
+
+  // Initialize BrokenImages
+  mBrokenImageUrls.assign(COUNT_BROKEN_IMAGE_MAX, "");
 }
 
 StyleManager::~StyleManager()
@@ -309,6 +314,17 @@ const Property::Map StyleManager::GetConfigurations()
   return result;
 }
 
+void StyleManager::SetBrokenImageUrl(BrokenImageType brokenImageType, const std::string& brokenImageUrl)
+{
+  mBrokenImageUrls[brokenImageType] = brokenImageUrl;
+  EmitStyleChangeSignals(StyleChange::THEME_CHANGE);
+}
+
+std::string StyleManager::GetBrokenImageUrl(BrokenImageType brokenImageType)
+{
+  return mBrokenImageUrls[brokenImageType];
+}
+
 bool StyleManager::LoadFile(const std::string& filename, std::string& stringOut)
 {
   DALI_ASSERT_DEBUG(0 != filename.length());
index b6eaff5..ef10d9a 100644 (file)
@@ -46,6 +46,17 @@ class StyleManager : public Dali::BaseObject, public ConnectionTracker
 {
 public:
   /**
+   * @brief The Type of BrokenImage
+   */
+  enum BrokenImageType
+  {
+    SMALL,
+    NORMAL,
+    LARGE
+  };
+
+public:
+  /**
    * Singleton access
    *
    * @return The StyleManager object
@@ -95,6 +106,16 @@ public: // Public API
   const Property::Map GetConfigurations();
 
   /**
+   * @copydoc Toolkit::DevelStyleManager::SetBrokenImageUrl
+   */
+  void SetBrokenImageUrl(BrokenImageType brokenImageType, const std::string& brokenImageUrl);
+
+  /**
+   * @copydoc Toolkit::DevelStyleManager::GetBrokenImageUrl
+   */
+  std::string GetBrokenImageUrl(BrokenImageType brokenImageType);
+
+  /**
    * @brief Apply the theme style to a control.
    *
    * @param[in] control The control to apply style.
@@ -233,6 +254,8 @@ private:
 
   Toolkit::Internal::FeedbackStyle* mFeedbackStyle; ///< Feedback style
 
+  std::vector<std::string> mBrokenImageUrls; ///< For brokenImage
+
   // Signals
   Toolkit::StyleManager::StyleChangedSignalType mControlStyleChangeSignal; ///< Emitted when the style( theme/font ) changes for the controls to style themselves
   Toolkit::StyleManager::StyleChangedSignalType mStyleChangedSignal;       ///< Emitted after the controls have been styled
index da54e1e..7d91e62 100644 (file)
@@ -807,9 +807,14 @@ TextureSet AnimatedImageVisual::SetLoadingFailed()
   DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "ResourceReady(ResourceStatus::FAILED)\n");
   ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
 
-  TextureSet textureSet  = TextureSet::New();
-  Texture    brokenImage = mFactoryCache.GetBrokenVisualImage();
-  textureSet.SetTexture(0u, brokenImage);
+  Actor actor = mPlacementActor.GetHandle();
+  Vector2 imageSize = Vector2::ZERO;
+  if(actor)
+  {
+    imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+  }
+  mFactoryCache.GetBrokenImageRenderer(mImpl->mRenderer, imageSize);
+  TextureSet textureSet = mImpl->mRenderer.GetTextures();
 
   if(mFrameDelayTimer)
   {
index 35d7456..0fef82d 100644 (file)
@@ -305,14 +305,10 @@ void AnimatedVectorImageVisual::DoSetOnScene(Actor& actor)
 
   if(mLoadFailed)
   {
-    TextureSet textureSet = TextureSet::New();
-    mImpl->mRenderer.SetTextures(textureSet);
-
-    Texture brokenImage = mFactoryCache.GetBrokenVisualImage();
-    textureSet.SetTexture(0u, brokenImage);
-
+    Vector2 imageSize = Vector2::ZERO;
+    imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+    mFactoryCache.GetBrokenImageRenderer(mImpl->mRenderer, imageSize);
     actor.AddRenderer(mImpl->mRenderer);
-
     ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
   }
   else
index 0251a1d..292f3f9 100644 (file)
@@ -513,8 +513,14 @@ void ImageVisual::GetNaturalSize(Vector2& naturalSize)
       }
       else
       {
-        Texture brokenImage = mFactoryCache.GetBrokenVisualImage();
-
+        Actor actor = mPlacementActor.GetHandle();
+        Vector2 imageSize = Vector2::ZERO;
+        if(actor)
+        {
+          imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+        }
+        mFactoryCache.GetBrokenImageRenderer(mImpl->mRenderer, imageSize);
+        Texture brokenImage = mImpl->mRenderer.GetTextures().GetTexture(0);
         naturalSize.x = brokenImage.GetWidth();
         naturalSize.y = brokenImage.GetWidth();
       }
@@ -710,12 +716,12 @@ void ImageVisual::DoSetOnScene(Actor& actor)
   }
   else if(mLoadState == TextureManager::LoadState::LOAD_FAILED)
   {
-    Texture brokenImage = mFactoryCache.GetBrokenVisualImage();
-
-    mTextures = TextureSet::New();
-    mTextures.SetTexture(0u, brokenImage);
-    mImpl->mRenderer.SetTextures(mTextures);
-
+    Vector2 imageSize = Vector2::ZERO;
+    if(actor)
+    {
+      imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+    }
+    mFactoryCache.GetBrokenImageRenderer(mImpl->mRenderer, imageSize);
     actor.AddRenderer(mImpl->mRenderer);
     mPlacementActor.Reset();
 
@@ -860,26 +866,30 @@ void ImageVisual::UploadComplete(bool loadingSuccess, int32_t textureId, Texture
     EnablePreMultipliedAlpha(preMultiplied);
 
     Actor actor = mPlacementActor.GetHandle();
-    if(actor)
+    if(!loadingSuccess)
     {
-      actor.AddRenderer(mImpl->mRenderer);
-      // reset the weak handle so that the renderer only get added to actor once
-      mPlacementActor.Reset();
+      Vector2 imageSize = Vector2::ZERO;
+      if(actor)
+      {
+        imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+      }
+      mFactoryCache.GetBrokenImageRenderer(mImpl->mRenderer, imageSize);
+      textureSet = mImpl->mRenderer.GetTextures();
     }
-
-    if(!loadingSuccess)
+    else
     {
-      Texture brokenImage = mFactoryCache.GetBrokenVisualImage();
-
-      textureSet = TextureSet::New();
-      textureSet.SetTexture(0u, brokenImage);
+      Sampler sampler = Sampler::New();
+      sampler.SetWrapMode(mWrapModeU, mWrapModeV);
+      textureSet.SetSampler(0u, sampler);
       mImpl->mRenderer.SetTextures(textureSet);
     }
 
-    Sampler sampler = Sampler::New();
-    sampler.SetWrapMode(mWrapModeU, mWrapModeV);
-    textureSet.SetSampler(0u, sampler);
-    mImpl->mRenderer.SetTextures(textureSet);
+    if(actor)
+    {
+      actor.AddRenderer(mImpl->mRenderer);
+      // reset the weak handle so that the renderer only get added to actor once
+      mPlacementActor.Reset();
+    }
   }
 
   // Storing TextureSet needed when renderer staged.
index 5f8ddff..cb2850d 100644 (file)
@@ -104,7 +104,6 @@ std::size_t NPatchLoader::Load(TextureManager& textureManager, TextureUploadObse
             newData->AddObserver(textureObserver);
 
             mCache.PushBack(newData);
-
             return newData->GetId(); // valid ids start from 1u
           }
         }
@@ -133,7 +132,6 @@ std::size_t NPatchLoader::Load(TextureManager& textureManager, TextureUploadObse
     preMultiplyOnLoad = (preMultiplyOnLoading == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD) ? true : false;
     data->SetLoadedNPatchData(pixelBuffer, preMultiplyOnLoad);
   }
-
   return data->GetId();
 }
 
index d9c26aa..aea229b 100644 (file)
@@ -562,7 +562,14 @@ void NPatchVisual::ApplyTextureAndUniforms()
     DALI_LOG_ERROR("The N patch image '%s' is not a valid N patch image\n", mImageUrl.GetUrl().c_str());
     textureSet = TextureSet::New();
 
-    Texture croppedImage = mFactoryCache.GetBrokenVisualImage();
+    Actor actor = mPlacementActor.GetHandle();
+    Vector2 imageSize = Vector2::ZERO;
+    if(actor)
+    {
+      imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+    }
+    mFactoryCache.GetBrokenImageRenderer(mImpl->mRenderer, imageSize);
+    Texture croppedImage = mImpl->mRenderer.GetTextures().GetTexture(0);
     textureSet.SetTexture(0u, croppedImage);
     mImpl->mRenderer.RegisterProperty("uFixed[0]", Vector2::ZERO);
     mImpl->mRenderer.RegisterProperty("uFixed[1]", Vector2::ZERO);
index 67fd435..2dbbffe 100644 (file)
@@ -157,9 +157,9 @@ void SvgVisual::DoSetOnScene(Actor& actor)
 
   if(mLoadFailed)
   {
-    Texture brokenImage = mFactoryCache.GetBrokenVisualImage();
-    textureSet.SetTexture(0u, brokenImage);
-
+    Vector2 imageSize = Vector2::ZERO;
+    imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+    mFactoryCache.GetBrokenImageRenderer(mImpl->mRenderer, imageSize);
     actor.AddRenderer(mImpl->mRenderer);
 
     ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
@@ -327,11 +327,9 @@ void SvgVisual::ApplyRasterizedImage(VectorImageRenderer vectorRenderer, PixelDa
     Actor actor = mPlacementActor.GetHandle();
     if(actor)
     {
-      TextureSet textureSet = mImpl->mRenderer.GetTextures();
-
-      Texture brokenImage = mFactoryCache.GetBrokenVisualImage();
-      textureSet.SetTexture(0u, brokenImage);
-
+      Vector2 imageSize = Vector2::ZERO;     
+      imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+      mFactoryCache.GetBrokenImageRenderer(mImpl->mRenderer, imageSize);
       actor.AddRenderer(mImpl->mRenderer);
     }
 
index b4fde0a..83bf574 100644 (file)
@@ -26,6 +26,8 @@
 #include <dali-toolkit/internal/visuals/color/color-visual.h>
 #include <dali-toolkit/internal/visuals/image-atlas-manager.h>
 #include <dali-toolkit/internal/visuals/svg/svg-visual.h>
+#include <dali/integration-api/debug.h>
+#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
 
 namespace Dali
 {
@@ -33,12 +35,72 @@ namespace Toolkit
 {
 namespace Internal
 {
+namespace
+{
+
+static constexpr int32_t COUNT_BROKEN_IMAGE_MAX = 3;
+
+/**
+ * @brief Creates the geometry formed from the vertices and indices
+ *
+ * @param[in]  vertices             The vertices to generate the geometry from
+ * @param[in]  indices              The indices to generate the geometry from
+ * @return The geometry formed from the vertices and indices
+ */
+Geometry GenerateGeometry(const Vector<Vector2>& vertices, const Vector<unsigned short>& indices)
+{
+  Property::Map vertexFormat;
+  vertexFormat["aPosition"] = Property::VECTOR2;
+  VertexBuffer vertexBuffer = VertexBuffer::New(vertexFormat);
+  if(vertices.Size() > 0)
+  {
+    vertexBuffer.SetData(&vertices[0], vertices.Size());
+  }
+
+  // Create the geometry object
+  Geometry geometry = Geometry::New();
+  geometry.AddVertexBuffer(vertexBuffer);
+  if(indices.Size() > 0)
+  {
+    geometry.SetIndexBuffer(&indices[0], indices.Size());
+  }
+
+  return geometry;
+}
+
+/**
+ * @brief Adds the indices to form a quad composed off two triangles where the indices are organised in a grid
+ *
+ * @param[out] indices     The indices to add to
+ * @param[in]  rowIdx      The row index to start the quad
+ * @param[in]  nextRowIdx  The index to the next row
+ */
+void AddQuadIndices(Vector<unsigned short>& indices, unsigned int rowIdx, unsigned int nextRowIdx)
+{
+  indices.PushBack(rowIdx);
+  indices.PushBack(nextRowIdx + 1);
+  indices.PushBack(rowIdx + 1);
+
+  indices.PushBack(rowIdx);
+  indices.PushBack(nextRowIdx);
+  indices.PushBack(nextRowIdx + 1);
+}
+
+void AddVertex(Vector<Vector2>& vertices, unsigned int x, unsigned int y)
+{
+  vertices.PushBack(Vector2(x, y));
+}
+
+} //unnamed namespace
+
 VisualFactoryCache::VisualFactoryCache(bool preMultiplyOnLoad)
 : mSvgRasterizeThread(NULL),
   mVectorAnimationManager(),
-  mBrokenImageUrl(""),
-  mPreMultiplyOnLoad(preMultiplyOnLoad)
+  mPreMultiplyOnLoad(preMultiplyOnLoad),
+  mBrokenImageInfoContainer(),
+  mUseCustomBrokenImage(false)
 {
+  mBrokenImageInfoContainer.assign(COUNT_BROKEN_IMAGE_MAX, BrokenImageInfo());
 }
 
 VisualFactoryCache::~VisualFactoryCache()
@@ -104,7 +166,7 @@ ImageAtlasManagerPtr VisualFactoryCache::GetAtlasManager()
   if(!mAtlasManager)
   {
     mAtlasManager = new ImageAtlasManager();
-    mAtlasManager->SetBrokenImage(mBrokenImageUrl);
+    mAtlasManager->SetBrokenImage(mBrokenImageInfoContainer[BrokenImageType::SMALL].url);
   }
 
   return mAtlasManager;
@@ -207,20 +269,22 @@ Geometry VisualFactoryCache::CreateGridGeometry(Uint16Pair gridSize)
   return geometry;
 }
 
-Texture VisualFactoryCache::GetBrokenVisualImage()
+Texture VisualFactoryCache::GetBrokenVisualImage(BrokenImageType brokenImageType)
 {
-  if(!mBrokenImageTexture && mBrokenImageUrl.size())
+  if(!(mBrokenImageInfoContainer[brokenImageType].texture) && !mBrokenImageInfoContainer[brokenImageType].url.empty())
   {
-    PixelData          data;
-    Devel::PixelBuffer pixelBuffer = LoadImageFromFile(mBrokenImageUrl);
+    PixelData          pixelData;
+    Devel::PixelBuffer pixelBuffer = LoadImageFromFile(mBrokenImageInfoContainer[brokenImageType].url);
     if(pixelBuffer)
     {
-      data                = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
-      mBrokenImageTexture = Texture::New(Dali::TextureType::TEXTURE_2D, data.GetPixelFormat(), data.GetWidth(), data.GetHeight());
-      mBrokenImageTexture.Upload(data);
+      pixelData                = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
+      mBrokenImageInfoContainer[brokenImageType].texture  = Texture::New(Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight());
+      mBrokenImageInfoContainer[brokenImageType].texture.Upload(pixelData);
+      mBrokenImageInfoContainer[brokenImageType].width = pixelData.GetWidth();
+      mBrokenImageInfoContainer[brokenImageType].height = pixelData.GetHeight();
     }
   }
-  return mBrokenImageTexture;
+  return mBrokenImageInfoContainer[brokenImageType].texture;
 }
 
 void VisualFactoryCache::SetPreMultiplyOnLoad(bool preMultiply)
@@ -233,16 +297,290 @@ bool VisualFactoryCache::GetPreMultiplyOnLoad()
   return mPreMultiplyOnLoad;
 }
 
-void VisualFactoryCache::SetBrokenImageUrl(const std::string& brokenImageUrl)
+void VisualFactoryCache::EnableCustomBrokenImage(bool enabled)
+{
+  mUseCustomBrokenImage = enabled;
+}
+
+void VisualFactoryCache::SetBrokenImageUrl(BrokenImageType brokenImageType, const std::string& brokenImageUrl)
 {
-  mBrokenImageUrl = brokenImageUrl;
+  const NPatchData* data;
+  mBrokenImageInfoContainer[brokenImageType].url = brokenImageUrl;
 
   if(!mAtlasManager)
   {
     mAtlasManager = new ImageAtlasManager();
   }
 
-  mAtlasManager->SetBrokenImage(mBrokenImageUrl);
+  mAtlasManager->SetBrokenImage(mBrokenImageInfoContainer[brokenImageType].url);
+
+  // Update BrokenImageType
+  if(!mBrokenImageInfoContainer[brokenImageType].url.empty())
+  {
+    Rect<int> border;
+    VisualUrl visualUrl(mBrokenImageInfoContainer[brokenImageType].url);
+    mBrokenImageInfoContainer[brokenImageType].visualType = visualUrl.GetType();
+    if(mBrokenImageInfoContainer[brokenImageType].visualType == VisualUrl::Type::N_PATCH)
+    {
+      mBrokenImageInfoContainer[brokenImageType].npatchId = mNPatchLoader.Load( mTextureManager, NULL, mBrokenImageInfoContainer[brokenImageType].url, border, mPreMultiplyOnLoad, true);
+      if(mNPatchLoader.GetNPatchData(mBrokenImageInfoContainer[brokenImageType].npatchId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
+      {
+        mBrokenImageInfoContainer[brokenImageType].width = data->GetCroppedWidth();
+        mBrokenImageInfoContainer[brokenImageType].height = data->GetCroppedHeight();
+      }
+    }
+    else
+    {
+      GetBrokenVisualImage(brokenImageType);
+    }
+  }
+}
+
+VisualUrl::Type VisualFactoryCache::GetBrokenImageVisualType(BrokenImageType brokenImageType)
+{
+  return mBrokenImageInfoContainer[brokenImageType].visualType;
+}
+
+Geometry VisualFactoryCache::CreateNPatchGeometry(Uint16Pair gridSize)
+{
+  uint16_t gridWidth  = gridSize.GetWidth();
+  uint16_t gridHeight = gridSize.GetHeight();
+
+  // Create vertices
+  Vector<Vector2> vertices;
+  vertices.Reserve((gridWidth + 1) * (gridHeight + 1));
+
+  for(int y = 0; y < gridHeight + 1; ++y)
+  {
+    for(int x = 0; x < gridWidth + 1; ++x)
+    {
+      AddVertex(vertices, x, y);
+    }
+  }
+
+  // Create indices
+  Vector<unsigned short> indices;
+  indices.Reserve(gridWidth * gridHeight * 6);
+
+  unsigned int rowIdx     = 0;
+  unsigned int nextRowIdx = gridWidth + 1;
+  for(int y = 0; y < gridHeight; ++y, ++nextRowIdx, ++rowIdx)
+  {
+    for(int x = 0; x < gridWidth; ++x, ++nextRowIdx, ++rowIdx)
+    {
+      AddQuadIndices(indices, rowIdx, nextRowIdx);
+    }
+  }
+
+  return GenerateGeometry(vertices, indices);
+}
+
+Geometry VisualFactoryCache::GetNPatchGeometry(BrokenImageType brokenImageType)
+{
+  Geometry          geometry;
+  const NPatchData* data;
+  if(mNPatchLoader.GetNPatchData(mBrokenImageInfoContainer[brokenImageType].npatchId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
+  {
+    if(data->GetStretchPixelsX().Size() == 1 && data->GetStretchPixelsY().Size() == 1)
+    {
+      geometry = GetGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY);
+      if(!geometry)
+      {
+        geometry = CreateNPatchGeometry(Uint16Pair(3,3));
+        SaveGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY, geometry);
+      }
+    }
+    else if(data->GetStretchPixelsX().Size() > 0 || data->GetStretchPixelsY().Size() > 0)
+    {
+      Uint16Pair gridSize(2 * data->GetStretchPixelsX().Size() + 1, 2 * data->GetStretchPixelsY().Size() + 1);
+      if(!data->GetRenderingMap())
+      {
+        geometry = CreateNPatchGeometry(gridSize);
+      }
+    }
+  }
+  else
+  {
+    // no N patch data so use default geometry
+    geometry = GetGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY);
+    if(!geometry)
+    {
+      geometry = CreateNPatchGeometry(Uint16Pair(3,3));
+      SaveGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY, geometry);
+    }
+  }
+  return geometry;
+}
+
+Shader VisualFactoryCache::GetNPatchShader(BrokenImageType brokenImageType)
+{
+  Shader            shader;
+  const NPatchData* data;
+  // 0 is either no data (load failed?) or no stretch regions on image
+  // for both cases we use the default shader
+  NPatchUtility::StretchRanges::SizeType xStretchCount = 0;
+  NPatchUtility::StretchRanges::SizeType yStretchCount = 0;
+
+  // ask loader for the regions
+  if(mNPatchLoader.GetNPatchData(mBrokenImageInfoContainer[brokenImageType].npatchId, data))
+  {
+    xStretchCount = data->GetStretchPixelsX().Count();
+    yStretchCount = data->GetStretchPixelsY().Count();
+  }
+
+  if(DALI_LIKELY((xStretchCount == 1 && yStretchCount == 1) ||
+                 (xStretchCount == 0 && yStretchCount == 0)))
+  {
+    shader = GetShader(VisualFactoryCache::NINE_PATCH_SHADER);
+    if(DALI_UNLIKELY(!shader))
+    {
+      shader = Shader::New(SHADER_NPATCH_VISUAL_3X3_SHADER_VERT, SHADER_NPATCH_VISUAL_SHADER_FRAG);
+
+      // Only cache vanilla 9 patch shaders
+      SaveShader(VisualFactoryCache::NINE_PATCH_SHADER, shader);
+    }
+  }
+  else if(xStretchCount > 0 || yStretchCount > 0)
+  {
+    std::stringstream vertexShader;
+    vertexShader << "#define FACTOR_SIZE_X " << xStretchCount + 2 << "\n"
+                 << "#define FACTOR_SIZE_Y " << yStretchCount + 2 << "\n"
+                 << SHADER_NPATCH_VISUAL_SHADER_VERT;
+    shader = Shader::New(vertexShader.str(), SHADER_NPATCH_VISUAL_SHADER_FRAG);
+  }
+  return shader;
+}
+
+void VisualFactoryCache::RegisterStretchProperties(Renderer& renderer, BrokenImageType brokenImageType, const char* uniformName, const NPatchUtility::StretchRanges& stretchPixels, uint16_t imageExtent)
+{
+  uint16_t     prevEnd     = 0;
+  uint16_t     prevFix     = 0;
+  uint16_t     prevStretch = 0;
+  unsigned int i           = 1;
+  for(NPatchUtility::StretchRanges::ConstIterator it = stretchPixels.Begin(); it != stretchPixels.End(); ++it, ++i)
+  {
+    uint16_t start = it->GetX();
+    uint16_t end   = it->GetY();
+
+    uint16_t fix     = prevFix + start - prevEnd;
+    uint16_t stretch = prevStretch + end - start;
+
+    std::stringstream uniform;
+    uniform << uniformName << "[" << i << "]";
+    renderer.RegisterProperty(uniform.str(), Vector2(fix, stretch));
+
+    prevEnd     = end;
+    prevFix     = fix;
+    prevStretch = stretch;
+  }
+
+  {
+    prevFix += imageExtent - prevEnd;
+    std::stringstream uniform;
+    uniform << uniformName << "[" << i << "]";
+    renderer.RegisterProperty(uniform.str(), Vector2(prevFix, prevStretch));
+  }
+}
+
+void VisualFactoryCache::ApplyTextureAndUniforms(Renderer& renderer, BrokenImageType brokenImageType)
+{
+  const NPatchData* data;
+  TextureSet        textureSet;
+  if(mNPatchLoader.GetNPatchData(mBrokenImageInfoContainer[brokenImageType].npatchId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
+  {
+    textureSet = data->GetTextures();
+    mBrokenImageInfoContainer[brokenImageType].texture = data->GetTextures().GetTexture(0);
+
+    if(data->GetStretchPixelsX().Size() == 1 && data->GetStretchPixelsY().Size() == 1)
+    {
+      //special case for 9 patch
+      Uint16Pair stretchX = data->GetStretchPixelsX()[0];
+      Uint16Pair stretchY = data->GetStretchPixelsY()[0];
+
+      uint16_t stretchWidth  = (stretchX.GetY() >= stretchX.GetX()) ? stretchX.GetY() - stretchX.GetX() : 0;
+      uint16_t stretchHeight = (stretchY.GetY() >= stretchY.GetX()) ? stretchY.GetY() - stretchY.GetX() : 0;
+
+      renderer.RegisterProperty("uFixed[0]", Vector2::ZERO);
+      renderer.RegisterProperty("uFixed[1]", Vector2(stretchX.GetX(), stretchY.GetX()));
+      renderer.RegisterProperty("uFixed[2]", Vector2(data->GetCroppedWidth() - stretchWidth, data->GetCroppedHeight() - stretchHeight));
+      renderer.RegisterProperty("uStretchTotal", Vector2(stretchWidth, stretchHeight));
+    }
+    else
+    {
+      renderer.RegisterProperty("uNinePatchFactorsX[0]", Vector2::ZERO);
+      renderer.RegisterProperty("uNinePatchFactorsY[0]", Vector2::ZERO);
+
+      RegisterStretchProperties(renderer, brokenImageType, "uNinePatchFactorsX", data->GetStretchPixelsX(), data->GetCroppedWidth());
+      RegisterStretchProperties(renderer, brokenImageType, "uNinePatchFactorsY", data->GetStretchPixelsY(), data->GetCroppedHeight());
+    }
+  }
+  else
+  {
+    textureSet = TextureSet::New();
+
+    Texture croppedImage = GetBrokenVisualImage(brokenImageType);
+    textureSet.SetTexture(0u, croppedImage);
+    renderer.RegisterProperty("uFixed[0]", Vector2::ZERO);
+    renderer.RegisterProperty("uFixed[1]", Vector2::ZERO);
+    renderer.RegisterProperty("uFixed[2]", Vector2::ZERO);
+    renderer.RegisterProperty("uStretchTotal", Vector2(croppedImage.GetWidth(), croppedImage.GetHeight()));
+  }
+
+  renderer.SetTextures(textureSet);
+}
+
+void VisualFactoryCache::GetBrokenImageRenderer(Renderer& renderer, const Vector2& size)
+{
+  BrokenImageType brokenImageType = GetProperBrokenImageType(size);
+
+  if(GetBrokenImageVisualType(brokenImageType) == VisualUrl::N_PATCH)
+  {
+    // Set geometry and shader for npatch
+    Geometry geometry = GetNPatchGeometry(brokenImageType);
+    Shader shader = GetNPatchShader(brokenImageType);
+    renderer.SetGeometry(geometry);
+    renderer.SetShader(shader);
+    ApplyTextureAndUniforms(renderer, brokenImageType);
+  }
+  else
+  {
+    Texture brokenImage = GetBrokenVisualImage(brokenImageType);
+    TextureSet textureSet = TextureSet::New();
+    textureSet.SetTexture(0u, brokenImage);
+    renderer.SetTextures(textureSet);
+  }
+}
+
+VisualFactoryCache::BrokenImageType VisualFactoryCache::GetProperBrokenImageType(const Vector2& size)
+{
+  // Sets the default broken type
+  BrokenImageType returnType = BrokenImageType::SMALL;
+
+  if((size.width == 0 && size.height == 0) || !mUseCustomBrokenImage )
+  {
+    // To do : Need to add observer about size
+    // Can't get size , just use default size of brokenImage
+    return returnType;
+  }
+
+  // Find the proper value if we know the size of the image
+  for(auto brokenImageIter = mBrokenImageInfoContainer.rbegin(); brokenImageIter != mBrokenImageInfoContainer.rend(); brokenImageIter++)
+  {
+    // Skip if the value is not set
+    if(brokenImageIter->width == 0 && brokenImageIter->height == 0)
+    {
+      continue;
+    }
+
+    if(brokenImageIter->width < size.width && brokenImageIter->height < size.height)
+    {
+      int index = std::distance(brokenImageIter,mBrokenImageInfoContainer.rend()-1);
+      returnType = (BrokenImageType)index;
+      break;
+    }
+  }
+
+  return returnType;
 }
 
 } // namespace Internal
index 6e8f37d..d7e390f 100644 (file)
@@ -28,6 +28,7 @@
 #include <dali-toolkit/internal/visuals/npatch-loader.h>
 #include <dali-toolkit/internal/visuals/svg/svg-rasterize-thread.h>
 #include <dali-toolkit/internal/visuals/texture-manager-impl.h>
+#include <dali/devel-api/rendering/renderer-devel.h>
 
 namespace Dali
 {
@@ -124,7 +125,18 @@ public:
     GEOMETRY_TYPE_MAX = WIREFRAME_GEOMETRY
   };
 
+  /**
+   * @brief The Type of BrokenImage
+   */
+  enum BrokenImageType
+  {
+    SMALL,
+    NORMAL,
+    LARGE
+  };
+
 public:
+
   /**
    * @brief Constructor
    *
@@ -177,12 +189,6 @@ public:
   static Geometry CreateGridGeometry(Uint16Pair gridSize);
 
   /**
-   * @brief Returns a new Texture to use when a visual has failed to correctly render
-   * @return The broken image texture.
-   */
-  Texture GetBrokenVisualImage();
-
-  /**
    * @copydoc Toolkit::VisualFactory::SetPreMultiplyOnLoad()
    */
   void SetPreMultiplyOnLoad(bool preMultiply);
@@ -193,10 +199,32 @@ public:
   bool GetPreMultiplyOnLoad();
 
   /**
+   * @brief Enable a custom broken image
+   *
+   * @param[in] enabled True if cache use custom broken image
+   */
+  void EnableCustomBrokenImage(bool enabled);
+
+  /**
    * @brief Set an image to be used when a visual has failed to correctly render
-   * @param[in] brokenImageUrl The broken image url.
+   * @param[in] brokenImageType BrokenImage type
+   * @param[in] brokenImageUrl The broken image url
+   */
+  void SetBrokenImageUrl(BrokenImageType brokenImageType, const std::string& brokenImageUrl);
+
+  /**
+   * @brief Returns a broken image type
+   * @param[in] brokenImageType BrokenImage type
+   * @return The broken image type.
+   */
+  VisualUrl::Type GetBrokenImageVisualType(BrokenImageType brokenImageType);
+
+  /**
+   * @brief Get the Npatch Renderer object
+   * @param[in] renderer renderer for npatch
+   * @param[in] size     the size of actor
    */
-  void SetBrokenImageUrl(const std::string& brokenImageUrl);
+  void GetBrokenImageRenderer(Renderer& renderer, const Vector2& size);
 
 public:
   /**
@@ -241,17 +269,101 @@ protected:
   VisualFactoryCache& operator=(const VisualFactoryCache& rhs);
 
 private:
+  /**
+   * @brief Returns a new Texture to use when a visual has failed to correctly render
+   * @return The broken image texture.
+   */
+  Texture GetBrokenVisualImage(BrokenImageType brokenImageType);
+
+  /**
+   * @brief Change the Proper broken image type
+   * @param[in] size The size of actor
+   *
+   * @return The type of broken image
+   */
+  BrokenImageType GetProperBrokenImageType(const Vector2& size);
+
+  /**
+   * @brief Apply a texture and uniforms
+   *
+   * @param renderer The renderer for broken image
+   * @param brokenImageType The type of broken image
+   */
+  void ApplyTextureAndUniforms(Renderer& renderer, BrokenImageType brokenImageType);
+
+  /**
+   * @brief Creates a Npatch Geometry object
+   *
+   * @param[in] gridSize The gridSize for creating a geometry
+   * @return The Geometry for NPatch
+   */
+  Geometry CreateNPatchGeometry(Uint16Pair gridSize);
+
+  /**
+   * @brief Gets a geometry for npatch image
+   *
+   * @param[in] brokenImageType the type of broken image
+   * @return The Geometry for NPatch
+   */
+  Geometry GetNPatchGeometry(BrokenImageType brokenImageType);
+
+  /**
+   * @brief Gets the Npatch Shader object
+   *
+   * @param[in] brokenImageType The type of broken image
+   * @return The Shader for NPatch
+   */
+  Shader GetNPatchShader(BrokenImageType brokenImageType);
+
+  /**
+   * @brief Registers a properties for Stretch Ranges
+   *
+   * @param renderer The renderer for broken image
+   * @param brokenImageType The type of broken image
+   * @param uniformName The name of the uniform
+   * @param stretchPixels The stretchable pixels in the cropped image space
+   * @param imageExtent The imageExtent
+   */
+  void RegisterStretchProperties(Renderer& renderer, BrokenImageType brokenImageType, const char* uniformName, const NPatchUtility::StretchRanges& stretchPixels, uint16_t imageExtent);
+
+private:
+  struct BrokenImageInfo
+  {
+    BrokenImageInfo()
+    :visualType(),
+     url(""),
+     npatchId(NPatchData::INVALID_NPATCH_DATA_ID),
+     texture(),
+     width(0),
+     height(0)
+    {
+    }
+
+    ~BrokenImageInfo()
+    {
+    }
+
+    // Data
+    VisualUrl::Type                         visualType;
+    std::string                             url;
+    NPatchData::NPatchDataId                npatchId;
+    Texture                                 texture;
+    uint32_t                                width;
+    uint32_t                                height;
+  };
+
   Geometry mGeometry[GEOMETRY_TYPE_MAX + 1];
   Shader   mShader[SHADER_TYPE_MAX + 1];
 
   ImageAtlasManagerPtr                    mAtlasManager;
   TextureManager                          mTextureManager;
   NPatchLoader                            mNPatchLoader;
-  Texture                                 mBrokenImageTexture;
+
   SvgRasterizeThread*                     mSvgRasterizeThread;
   std::unique_ptr<VectorAnimationManager> mVectorAnimationManager;
-  std::string                             mBrokenImageUrl;
   bool                                    mPreMultiplyOnLoad;
+  std::vector<BrokenImageInfo>            mBrokenImageInfoContainer;
+  bool                                    mUseCustomBrokenImage;
 };
 
 } // namespace Internal
index 8c4b2f8..ab4a15b 100644 (file)
@@ -61,6 +61,8 @@ namespace
 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_CONTROL_VISUALS");
 #endif
 
+static constexpr int32_t COUNT_BROKEN_IMAGE_MAX = 3;
+
 BaseHandle Create()
 {
   BaseHandle handle = Toolkit::VisualFactory::Get();
@@ -91,16 +93,7 @@ void VisualFactory::OnStyleChangedSignal(Toolkit::StyleManager styleManager, Sty
 {
   if(type == StyleChange::THEME_CHANGE)
   {
-    const std::string imageDirPath   = AssetManager::GetDaliImagePath();
-    std::string       brokenImageUrl = imageDirPath + BROKEN_IMAGE_FILE_NAME;
-
-    Property::Map config = Toolkit::DevelStyleManager::GetConfigurations(styleManager);
-    config["brokenImageUrl"].Get(brokenImageUrl);
-
-    if(mFactoryCache)
-    {
-      mFactoryCache->SetBrokenImageUrl(brokenImageUrl);
-    }
+    SetBrokenImageUrl(styleManager);
   }
 }
 
@@ -370,24 +363,65 @@ Internal::TextureManager& VisualFactory::GetTextureManager()
   return GetFactoryCache().GetTextureManager();
 }
 
-Internal::VisualFactoryCache& VisualFactory::GetFactoryCache()
+void VisualFactory::SetBrokenImageUrl(Toolkit::StyleManager& styleManager)
 {
-  if(!mFactoryCache)
+  const std::string imageDirPath   = AssetManager::GetDaliImagePath();
+  std::string       brokenImageUrl = imageDirPath + BROKEN_IMAGE_FILE_NAME;
+  std::string       customBrokenImageUrl[COUNT_BROKEN_IMAGE_MAX];
+
+  if(styleManager)
   {
-    mFactoryCache = std::unique_ptr<VisualFactoryCache>(new VisualFactoryCache(mPreMultiplyOnLoad));
+    Property::Map config = Toolkit::DevelStyleManager::GetConfigurations(styleManager);
+    config["brokenImageUrl"].Get(brokenImageUrl);
+    styleManager.StyleChangedSignal().Connect(mSlotDelegate, &VisualFactory::OnStyleChangedSignal);
 
-    const std::string imageDirPath   = AssetManager::GetDaliImagePath();
-    std::string       brokenImageUrl = imageDirPath + BROKEN_IMAGE_FILE_NAME;
+    bool findCustomBrokenImage = false;
+    for(int i=0;i<COUNT_BROKEN_IMAGE_MAX;i++)
+    {
+      customBrokenImageUrl[i] = Toolkit::DevelStyleManager::GetBrokenImageUrl(styleManager,Toolkit::DevelStyleManager::BrokenImageType(i));
+      if(!customBrokenImageUrl[i].empty())
+      {
+        findCustomBrokenImage = true;
+      }
+    }
 
-    Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
-    if(styleManager)
+    if(findCustomBrokenImage)
     {
-      Property::Map config = Toolkit::DevelStyleManager::GetConfigurations(styleManager);
-      config["brokenImageUrl"].Get(brokenImageUrl);
-      styleManager.StyleChangedSignal().Connect(mSlotDelegate, &VisualFactory::OnStyleChangedSignal);
+      std::string customDefaultBrokenUrl = "";
+      mFactoryCache->EnableCustomBrokenImage(true);
+      customDefaultBrokenUrl = customBrokenImageUrl[0];
+
+      for(int i=0;i<COUNT_BROKEN_IMAGE_MAX;i++)
+      {
+        if(customDefaultBrokenUrl.empty())
+        {
+          if(!customBrokenImageUrl[i].empty())
+          {
+            customDefaultBrokenUrl = customBrokenImageUrl[i];
+            mFactoryCache->SetBrokenImageUrl(Toolkit::Internal::VisualFactoryCache::BrokenImageType::SMALL, customBrokenImageUrl[i]);
+          }
+        }
+        mFactoryCache->SetBrokenImageUrl(Toolkit::Internal::VisualFactoryCache::BrokenImageType(i), customBrokenImageUrl[i]);
+      }
+    }
+    else
+    {
+      mFactoryCache->SetBrokenImageUrl(Toolkit::Internal::VisualFactoryCache::BrokenImageType::SMALL, brokenImageUrl);
     }
+  }
+  else
+  {
+    mFactoryCache->SetBrokenImageUrl(Toolkit::Internal::VisualFactoryCache::BrokenImageType::SMALL, brokenImageUrl);
+  }
+}
 
-    mFactoryCache->SetBrokenImageUrl(brokenImageUrl);
+Internal::VisualFactoryCache& VisualFactory::GetFactoryCache()
+{
+  if(!mFactoryCache)
+  {
+    mFactoryCache = std::unique_ptr<VisualFactoryCache>(new VisualFactoryCache(mPreMultiplyOnLoad));
+    Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
+    SetBrokenImageUrl(styleManager);
   }
   return *mFactoryCache;
 }
index f038301..670567b 100644 (file)
@@ -90,6 +90,12 @@ protected:
 
 private:
   /**
+   * @brief Set the Broken Image url
+   *
+   */
+  void SetBrokenImageUrl(Toolkit::StyleManager& styleManager);
+
+  /**
    * Get the factory cache, creating it if necessary.
    */
   Internal::VisualFactoryCache& GetFactoryCache();