CanvasRenderer: Add RemoveDrawable() API
[platform/core/uifw/dali-adaptor.git] / dali / internal / canvas-renderer / ubuntu / canvas-renderer-impl-ubuntu.cpp
index 1be78b9..1d9cc02 100644 (file)
@@ -24,6 +24,7 @@
 
 // INTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/internal/canvas-renderer/common/drawable-group-impl.h>
 #include <dali/internal/canvas-renderer/common/drawable-impl.h>
 #include <dali/internal/imaging/common/pixel-buffer-impl.h>
 
@@ -56,8 +57,8 @@ CanvasRendererUbuntu::CanvasRendererUbuntu(const Vector2& viewBox)
   mTvgCanvas(nullptr),
   mTvgRoot(nullptr),
 #endif
-  mSize(0, 0),
-  mViewBox(0, 0),
+  mSize(Vector2::ZERO),
+  mViewBox(Vector2::ZERO),
   mChanged(false)
 {
   Initialize(viewBox);
@@ -66,19 +67,8 @@ CanvasRendererUbuntu::CanvasRendererUbuntu(const Vector2& viewBox)
 CanvasRendererUbuntu::~CanvasRendererUbuntu()
 {
 #ifdef THORVG_SUPPORT
-  for(DrawableVectorIterator it    = mDrawables.begin(),
-                             endIt = mDrawables.end();
-      it != endIt;
-      ++it)
-  {
-    Dali::CanvasRenderer::Drawable drawable = (*it).GetHandle();
-    if(DALI_UNLIKELY(!drawable))
-    {
-      continue;
-    }
-    Internal::Adaptor::Drawable& drawableImpl = GetImplementation(drawable);
-    drawableImpl.SetObject(nullptr);
-  }
+  mDrawables.clear();
+
   //Terminate ThorVG Engine
   tvg::Initializer::term(tvg::CanvasEngine::Sw);
 #endif
@@ -100,33 +90,28 @@ void CanvasRendererUbuntu::Initialize(const Vector2& viewBox)
   }
 
   MakeTargetBuffer(mSize);
-
-  auto scene = tvg::Scene::gen();
-  mTvgRoot   = scene.get();
-  mTvgCanvas->push(move(scene));
 #endif
 }
 
 bool CanvasRendererUbuntu::Commit()
 {
 #ifdef THORVG_SUPPORT
+  Mutex::ScopedLock lock(mMutex);
+
+  if(mSize.width < 1.0f || mSize.height < 1.0f)
+  {
+    DALI_LOG_ERROR("Size is zero [%p]\n", this);
+    return false;
+  }
+
   bool changed = false;
 
-  for(DrawableVectorIterator it    = mDrawables.begin(),
-                             endIt = mDrawables.end();
-      it != endIt;
-      ++it)
+  for(auto& it : mDrawables)
   {
-    Dali::CanvasRenderer::Drawable drawable = (*it).GetHandle();
-    if(DALI_UNLIKELY(!drawable))
-    {
-      continue;
-    }
-    Internal::Adaptor::Drawable& drawableImpl = GetImplementation(drawable);
-    if(drawableImpl.GetChanged())
+    if(HaveDrawablesChanged(it))
     {
+      UpdateDrawablesChanged(it, false);
       changed = true;
-      drawableImpl.SetChanged(false);
     }
   }
 
@@ -136,32 +121,39 @@ bool CanvasRendererUbuntu::Commit()
   }
   else
   {
-    if(!mPixelBuffer.GetBuffer())
+    if(!mPixelBuffer || !mPixelBuffer.GetBuffer())
     {
       MakeTargetBuffer(mSize);
       mChanged = false;
     }
   }
 
-  if(mSize.width < 1.0f || mSize.height < 1.0f)
+  if(mTvgCanvas->clear() != tvg::Result::Success)
   {
-    DALI_LOG_ERROR("Size is zero [%p]\n", this);
+    DALI_LOG_ERROR("ThorVG canvas clear fail [%p]\n", this);
     return false;
   }
 
-  if(mViewBox != mSize)
+  auto scene = tvg::Scene::gen();
+  mTvgRoot   = scene.get();
+  for(auto& it : mDrawables)
+  {
+    PushDrawableToGroup(it, mTvgRoot);
+  }
+
+  if(mViewBox != mSize && mViewBox.width != 0 && mViewBox.height != 0)
   {
     auto scaleX = mSize.width / mViewBox.width;
     auto scaleY = mSize.height / mViewBox.height;
     mTvgRoot->scale(scaleX < scaleY ? scaleX : scaleY);
   }
-  mTvgCanvas->update(mTvgRoot);
 
-  if(mTvgCanvas->draw() != tvg::Result::Success)
+  if(mTvgCanvas->push(move(scene)) != tvg::Result::Success)
   {
-    DALI_LOG_ERROR("ThorVG Draw fail [%p]\n", this);
+    DALI_LOG_ERROR("ThorVG canvas push fail [%p]\n", this);
     return false;
   }
+
   return true;
 #else
   return false;
@@ -176,46 +168,98 @@ Devel::PixelBuffer CanvasRendererUbuntu::GetPixelBuffer()
 bool CanvasRendererUbuntu::AddDrawable(Dali::CanvasRenderer::Drawable& drawable)
 {
 #ifdef THORVG_SUPPORT
-  bool exist = false;
-  for(DrawableVectorIterator it    = mDrawables.begin(),
-                             endIt = mDrawables.end();
-      it != endIt;
-      ++it)
+  Internal::Adaptor::Drawable& drawableImpl = GetImplementation(drawable);
+  if(drawableImpl.IsAdded())
   {
-    if((*it) == drawable)
+    DALI_LOG_ERROR("Already added [%p][%p]\n", this, &drawable);
+    return false;
+  }
+
+  drawableImpl.SetAdded(true);
+  mDrawables.push_back(drawable);
+  mChanged = true;
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+#ifdef THORVG_SUPPORT
+bool CanvasRendererUbuntu::HaveDrawablesChanged(const Dali::CanvasRenderer::Drawable& drawable) const
+{
+  const Internal::Adaptor::Drawable& drawableImpl = GetImplementation(drawable);
+  if(drawableImpl.GetChanged())
+  {
+    return true;
+  }
+
+  if(drawableImpl.GetType() == Drawable::Types::DRAWABLE_GROUP)
+  {
+    const Dali::CanvasRenderer::DrawableGroup& group             = static_cast<const Dali::CanvasRenderer::DrawableGroup&>(drawable);
+    const Internal::Adaptor::DrawableGroup&    drawableGroupImpl = Dali::GetImplementation(group);
+    DrawableGroup::DrawableVector              drawables         = drawableGroupImpl.GetDrawables();
+    for(auto& it : drawables)
     {
-      exist = true;
-      break;
+      if(HaveDrawablesChanged(it))
+      {
+        return true;
+      }
     }
   }
-  if(exist)
+
+  return false;
+}
+
+void CanvasRendererUbuntu::UpdateDrawablesChanged(Dali::CanvasRenderer::Drawable& drawable, bool changed)
+{
+  Internal::Adaptor::Drawable& drawableImpl = GetImplementation(drawable);
+  drawableImpl.SetChanged(changed);
+
+  if(drawableImpl.GetType() == Drawable::Types::DRAWABLE_GROUP)
   {
-    DALI_LOG_ERROR("Already added [%p]\n", this);
-    return false;
+    Dali::CanvasRenderer::DrawableGroup& group             = static_cast<Dali::CanvasRenderer::DrawableGroup&>(drawable);
+    Internal::Adaptor::DrawableGroup&    drawableGroupImpl = Dali::GetImplementation(group);
+    DrawableGroup::DrawableVector        drawables         = drawableGroupImpl.GetDrawables();
+    for(auto& it : drawables)
+    {
+      UpdateDrawablesChanged(it, changed);
+    }
   }
+}
+#endif
 
-  Internal::Adaptor::Drawable& drawableImpl = GetImplementation(drawable);
-  tvg::Paint*                  pDrawable    = static_cast<tvg::Paint*>(drawableImpl.GetObject());
-  if(!pDrawable)
+bool CanvasRendererUbuntu::IsCanvasChanged() const
+{
+#ifdef THORVG_SUPPORT
+  if(mChanged)
   {
-    DALI_LOG_ERROR("Invalid drawable object [%p]\n", this);
-    return false;
+    return true;
   }
-  if(mSize.width < 1.0f || mSize.height < 1.0f)
+
+  for(auto& it : mDrawables)
   {
-    DALI_LOG_ERROR("Size is zero [%p]\n", this);
-    return false;
+    if(HaveDrawablesChanged(it))
+    {
+      return true;
+    }
   }
+#endif
+  return false;
+}
 
-  if(mTvgRoot->push(std::unique_ptr<tvg::Paint>(pDrawable)) != tvg::Result::Success)
+bool CanvasRendererUbuntu::Rasterize()
+{
+#ifdef THORVG_SUPPORT
+  Mutex::ScopedLock lock(mMutex);
+
+  if(mTvgCanvas->draw() != tvg::Result::Success)
   {
-    DALI_LOG_ERROR("Tvg push fail [%p]\n", this);
+    DALI_LOG_ERROR("ThorVG Draw fail [%p]\n", this);
     return false;
   }
 
-  drawableImpl.SetDrawableAdded(true);
-  mDrawables.push_back(drawable);
-  mChanged = true;
+  mTvgCanvas->sync();
 
   return true;
 #else
@@ -223,6 +267,25 @@ bool CanvasRendererUbuntu::AddDrawable(Dali::CanvasRenderer::Drawable& drawable)
 #endif
 }
 
+bool CanvasRendererUbuntu::RemoveDrawable(Dali::CanvasRenderer::Drawable& drawable)
+{
+#ifdef THORVG_SUPPORT
+  DrawableGroup::DrawableVector::iterator it = std::find(mDrawables.begin(), mDrawables.end(), drawable);
+  if(it != mDrawables.end())
+  {
+    Internal::Adaptor::Drawable& drawableImpl = GetImplementation(drawable);
+    drawableImpl.SetAdded(false);
+
+    mDrawables.erase(it);
+    mChanged = true;
+
+    return true;
+  }
+
+#endif
+  return false;
+}
+
 bool CanvasRendererUbuntu::SetSize(const Vector2& size)
 {
   if(size.width < 1.0f || size.height < 1.0f)
@@ -232,12 +295,10 @@ bool CanvasRendererUbuntu::SetSize(const Vector2& size)
 
   if(size != mSize)
   {
-    mSize = size;
-    MakeTargetBuffer(size);
+    mSize    = size;
+    mChanged = true;
   }
 
-  mChanged = true;
-
   return true;
 }
 
@@ -246,6 +307,27 @@ const Vector2& CanvasRendererUbuntu::GetSize()
   return mSize;
 }
 
+bool CanvasRendererUbuntu::SetViewBox(const Vector2& viewBox)
+{
+  if(viewBox.width < 1.0f || viewBox.height < 1.0f)
+  {
+    return false;
+  }
+
+  if(viewBox != mViewBox)
+  {
+    mViewBox = viewBox;
+    mChanged = true;
+  }
+
+  return true;
+}
+
+const Vector2& CanvasRendererUbuntu::GetViewBox()
+{
+  return mViewBox;
+}
+
 void CanvasRendererUbuntu::MakeTargetBuffer(const Vector2& size)
 {
 #ifdef THORVG_SUPPORT
@@ -260,12 +342,70 @@ void CanvasRendererUbuntu::MakeTargetBuffer(const Vector2& size)
     return;
   }
 
-  mTvgCanvas->sync();
-
   mTvgCanvas->target(reinterpret_cast<uint32_t*>(pBuffer), size.width, size.width, size.height, tvg::SwCanvas::ABGR8888);
 #endif
 }
 
+#ifdef THORVG_SUPPORT
+void CanvasRendererUbuntu::PushDrawableToGroup(Dali::CanvasRenderer::Drawable& drawable, tvg::Scene* group)
+{
+  Internal::Adaptor::Drawable& drawableImpl        = Dali::GetImplementation(drawable);
+  tvg::Paint*                  tvgDuplicatedObject = static_cast<tvg::Paint*>(drawableImpl.GetObject())->duplicate();
+  if(!tvgDuplicatedObject)
+  {
+    DALI_LOG_ERROR("Invalid drawable object [%p]\n", this);
+    return;
+  }
+  Drawable::Types type = drawableImpl.GetType();
+
+  if(type == Drawable::Types::DRAWABLE_GROUP)
+  {
+    Dali::CanvasRenderer::DrawableGroup& group             = static_cast<Dali::CanvasRenderer::DrawableGroup&>(drawable);
+    Internal::Adaptor::DrawableGroup&    drawableGroupImpl = Dali::GetImplementation(group);
+    DrawableGroup::DrawableVector        drawables         = drawableGroupImpl.GetDrawables();
+    for(auto& it : drawables)
+    {
+      PushDrawableToGroup(it, static_cast<tvg::Scene*>(tvgDuplicatedObject));
+    }
+  }
+
+  Dali::CanvasRenderer::Drawable compositeDrawable = drawableImpl.GetCompositionDrawable();
+  if(DALI_UNLIKELY(compositeDrawable))
+  {
+    Internal::Adaptor::Drawable& compositeDrawableImpl = Dali::GetImplementation(compositeDrawable);
+    tvg::Paint*                  tvgCompositeObject    = static_cast<tvg::Paint*>(compositeDrawableImpl.GetObject());
+    if(tvgCompositeObject)
+    {
+      tvg::Paint*     tvgDuplicatedCompositeObject = tvgCompositeObject->duplicate();
+      Drawable::Types type                         = compositeDrawableImpl.GetType();
+
+      if(type == Drawable::Types::DRAWABLE_GROUP)
+      {
+        Dali::CanvasRenderer::DrawableGroup& compositeGroup             = static_cast<Dali::CanvasRenderer::DrawableGroup&>(compositeDrawable);
+        Internal::Adaptor::DrawableGroup&    compositeDrawableGroupImpl = Dali::GetImplementation(compositeGroup);
+        DrawableGroup::DrawableVector        compositeDrawables         = compositeDrawableGroupImpl.GetDrawables();
+        for(auto& it : compositeDrawables)
+        {
+          PushDrawableToGroup(it, static_cast<tvg::Scene*>(tvgDuplicatedCompositeObject));
+        }
+      }
+
+      if(tvgDuplicatedObject->composite(std::move(std::unique_ptr<tvg::Paint>(tvgDuplicatedCompositeObject)), static_cast<tvg::CompositeMethod>(drawableImpl.GetCompositionType())) != tvg::Result::Success)
+      {
+        DALI_LOG_ERROR("Tvg composite fail [%p]\n", this);
+        return;
+      }
+    }
+  }
+
+  if(group->push(std::move(std::unique_ptr<tvg::Paint>(tvgDuplicatedObject))) != tvg::Result::Success)
+  {
+    DALI_LOG_ERROR("Tvg push fail [%p]\n", this);
+    return;
+  }
+}
+#endif
+
 } // namespace Adaptor
 
 } // namespace Internal