CanvasRenderer: Refactoring to pass rasterized buffer
[platform/core/uifw/dali-adaptor.git] / dali / internal / canvas-renderer / tizen / canvas-renderer-impl-tizen.cpp
index b1b043c..bc45837 100644 (file)
 
 // 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/canvas-renderer/common/gradient-impl.h>
+#include <dali/internal/canvas-renderer/common/shape-impl.h>
 #include <dali/internal/imaging/common/pixel-buffer-impl.h>
 
 namespace Dali
@@ -51,13 +54,16 @@ CanvasRendererTizen* CanvasRendererTizen::New(const Vector2& viewBox)
 }
 
 CanvasRendererTizen::CanvasRendererTizen(const Vector2& viewBox)
-: mPixelBuffer(nullptr),
+:
 #ifdef THORVG_SUPPORT
+  mPixelBuffer(nullptr),
+  mRasterizedTexture(),
+  mMutex(),
   mTvgCanvas(nullptr),
   mTvgRoot(nullptr),
 #endif
-  mSize(0, 0),
-  mViewBox(0, 0),
+  mSize(Vector2::ZERO),
+  mViewBox(Vector2::ZERO),
   mChanged(false)
 {
   Initialize(viewBox);
@@ -66,19 +72,8 @@ CanvasRendererTizen::CanvasRendererTizen(const Vector2& viewBox)
 CanvasRendererTizen::~CanvasRendererTizen()
 {
 #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,34 +95,28 @@ void CanvasRendererTizen::Initialize(const Vector2& viewBox)
   }
 
   MakeTargetBuffer(mSize);
-
-  auto scene = tvg::Scene::gen();
-  mTvgRoot   = scene.get();
-  mTvgCanvas->push(move(scene));
 #endif
 }
 
 bool CanvasRendererTizen::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);
-      break;
     }
   }
 
@@ -137,85 +126,259 @@ bool CanvasRendererTizen::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;
 #endif
 }
 
-Devel::PixelBuffer CanvasRendererTizen::GetPixelBuffer()
+Dali::Texture CanvasRendererTizen::GetRasterizedTexture()
 {
-  return mPixelBuffer;
+#ifdef THORVG_SUPPORT
+  if(mPixelBuffer)
+  {
+    auto width  = mPixelBuffer.GetWidth();
+    auto height = mPixelBuffer.GetHeight();
+    if(width <= 0 || height <= 0)
+    {
+      return Dali::Texture();
+    }
+
+    Dali::PixelData pixelData = Devel::PixelBuffer::Convert(mPixelBuffer);
+
+    if(!mRasterizedTexture || mRasterizedTexture.GetWidth() != width || mRasterizedTexture.GetHeight() != height)
+    {
+      mRasterizedTexture = Dali::Texture::New(Dali::TextureType::TEXTURE_2D, Dali::Pixel::BGRA8888, width, height);
+    }
+
+    mRasterizedTexture.Upload(pixelData);
+  }
+  return mRasterizedTexture;
+#else
+  return Dali::Texture();
+#endif
 }
 
 bool CanvasRendererTizen::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())
+  {
+    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 CanvasRendererTizen::HaveDrawablesChanged(const Dali::CanvasRenderer::Drawable& drawable) const
+{
+  const Internal::Adaptor::Drawable& drawableImpl = GetImplementation(drawable);
+  if(drawableImpl.GetChanged())
+  {
+    return true;
+  }
+  Dali::CanvasRenderer::Drawable compositeDrawable = drawableImpl.GetCompositionDrawable();
+  if(DALI_UNLIKELY(compositeDrawable))
   {
-    if((*it) == drawable)
+    Internal::Adaptor::Drawable& compositeDrawableImpl = Dali::GetImplementation(compositeDrawable);
+    if(compositeDrawableImpl.GetChanged())
     {
-      exist = true;
-      break;
+      return true;
     }
   }
-  if(exist)
+
+  if(drawableImpl.GetType() == Drawable::Types::DRAWABLE_GROUP)
   {
-    DALI_LOG_ERROR("Already added [%p]\n", this);
-    return false;
+    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)
+    {
+      if(HaveDrawablesChanged(it))
+      {
+        return true;
+      }
+    }
+  }
+  else if(drawableImpl.GetType() == Drawable::Types::SHAPE)
+  {
+    const Dali::CanvasRenderer::Shape& shape        = static_cast<const Dali::CanvasRenderer::Shape&>(drawable);
+    Dali::CanvasRenderer::Gradient     fillGradient = shape.GetFillGradient();
+    if(DALI_UNLIKELY(fillGradient))
+    {
+      Internal::Adaptor::Gradient& fillGradientImpl = Dali::GetImplementation(fillGradient);
+      if(fillGradientImpl.GetChanged())
+      {
+        return true;
+      }
+    }
+
+    Dali::CanvasRenderer::Gradient strokeGradient = shape.GetStrokeGradient();
+    if(DALI_UNLIKELY(strokeGradient))
+    {
+      Internal::Adaptor::Gradient& strokeGradientImpl = Dali::GetImplementation(strokeGradient);
+      if(strokeGradientImpl.GetChanged())
+      {
+        return true;
+      }
+    }
   }
 
+  return false;
+}
+
+void CanvasRendererTizen::UpdateDrawablesChanged(Dali::CanvasRenderer::Drawable& drawable, bool changed)
+{
   Internal::Adaptor::Drawable& drawableImpl = GetImplementation(drawable);
-  tvg::Paint*                  pDrawable    = static_cast<tvg::Paint*>(drawableImpl.GetObject());
-  if(!pDrawable)
+  drawableImpl.SetChanged(changed);
+
+  Dali::CanvasRenderer::Drawable compositeDrawable = drawableImpl.GetCompositionDrawable();
+  if(DALI_UNLIKELY(compositeDrawable))
   {
-    DALI_LOG_ERROR("Invalid drawable object [%p]\n", this);
-    return false;
+    Internal::Adaptor::Drawable& compositeDrawableImpl = Dali::GetImplementation(compositeDrawable);
+    compositeDrawableImpl.SetChanged(changed);
   }
-  if(mSize.width < 1.0f || mSize.height < 1.0f)
+
+  if(drawableImpl.GetType() == Drawable::Types::DRAWABLE_GROUP)
   {
-    DALI_LOG_ERROR("Size is zero [%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);
+    }
   }
+  else if(drawableImpl.GetType() == Drawable::Types::SHAPE)
+  {
+    Dali::CanvasRenderer::Shape&   shape        = static_cast<Dali::CanvasRenderer::Shape&>(drawable);
+    Dali::CanvasRenderer::Gradient fillGradient = shape.GetFillGradient();
+    if(DALI_UNLIKELY(fillGradient))
+    {
+      Internal::Adaptor::Gradient& fillGradientImpl = Dali::GetImplementation(fillGradient);
+      fillGradientImpl.SetChanged(changed);
+    }
 
-  if(mTvgRoot->push(std::unique_ptr<tvg::Paint>(pDrawable)) != tvg::Result::Success)
+    Dali::CanvasRenderer::Gradient strokeGradient = shape.GetStrokeGradient();
+    if(DALI_UNLIKELY(strokeGradient))
+    {
+      Internal::Adaptor::Gradient& strokeGradientImpl = Dali::GetImplementation(strokeGradient);
+      strokeGradientImpl.SetChanged(changed);
+    }
+  }
+}
+#endif
+
+bool CanvasRendererTizen::IsCanvasChanged() const
+{
+#ifdef THORVG_SUPPORT
+  if(mChanged)
   {
-    DALI_LOG_ERROR("Tvg push fail [%p]\n", this);
+    return true;
+  }
+
+  for(auto& it : mDrawables)
+  {
+    if(HaveDrawablesChanged(it))
+    {
+      return true;
+    }
+  }
+#endif
+  return false;
+}
+
+bool CanvasRendererTizen::Rasterize()
+{
+#ifdef THORVG_SUPPORT
+  Mutex::ScopedLock lock(mMutex);
+
+  if(mTvgCanvas->draw() != tvg::Result::Success)
+  {
+    DALI_LOG_ERROR("ThorVG Draw fail [%p]\n", this);
     return false;
   }
 
-  drawableImpl.SetDrawableAdded(true);
-  mDrawables.push_back(drawable);
+  mTvgCanvas->sync();
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool CanvasRendererTizen::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 CanvasRendererTizen::RemoveAllDrawables()
+{
+#ifdef THORVG_SUPPORT
+  for(auto& it : mDrawables)
+  {
+    Internal::Adaptor::Drawable& drawableImpl = GetImplementation(it);
+    drawableImpl.SetAdded(false);
+  }
+
+  mDrawables.clear();
   mChanged = true;
 
   return true;
@@ -224,7 +387,7 @@ bool CanvasRendererTizen::AddDrawable(Dali::CanvasRenderer::Drawable& drawable)
 #endif
 }
 
-bool CanvasRendererTizen::SetSize(const Vector2& size)
+bool CanvasRendererTizen::SetSize(Vector2 size)
 {
   if(size.width < 1.0f || size.height < 1.0f)
   {
@@ -233,24 +396,43 @@ bool CanvasRendererTizen::SetSize(const Vector2& size)
 
   if(size != mSize)
   {
-    mSize = size;
-    MakeTargetBuffer(size);
+    mSize    = size;
+    mChanged = true;
   }
 
-  mChanged = true;
-
   return true;
 }
 
-const Vector2& CanvasRendererTizen::GetSize()
+Vector2 CanvasRendererTizen::GetSize() const
 {
   return mSize;
 }
 
+bool CanvasRendererTizen::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& CanvasRendererTizen::GetViewBox()
+{
+  return mViewBox;
+}
+
 void CanvasRendererTizen::MakeTargetBuffer(const Vector2& size)
 {
 #ifdef THORVG_SUPPORT
-  mPixelBuffer = Devel::PixelBuffer::New(size.width, size.height, Dali::Pixel::RGBA8888);
+  mPixelBuffer = Devel::PixelBuffer::New(size.width, size.height, Dali::Pixel::BGRA8888);
 
   unsigned char* pBuffer;
   pBuffer = mPixelBuffer.GetBuffer();
@@ -261,12 +443,109 @@ void CanvasRendererTizen::MakeTargetBuffer(const Vector2& size)
     return;
   }
 
-  mTvgCanvas->sync();
-
-  mTvgCanvas->target(reinterpret_cast<uint32_t*>(pBuffer), size.width, size.width, size.height, tvg::SwCanvas::ABGR8888);
+  mTvgCanvas->target(reinterpret_cast<uint32_t*>(pBuffer), size.width, size.width, size.height, tvg::SwCanvas::ARGB8888);
 #endif
 }
 
+#ifdef THORVG_SUPPORT
+void CanvasRendererTizen::PushDrawableToGroup(Dali::CanvasRenderer::Drawable& drawable, tvg::Scene* parent)
+{
+  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));
+    }
+  }
+  else if(type == Drawable::Types::SHAPE)
+  {
+    //FillGradient
+    Dali::CanvasRenderer::Shape&   shape        = static_cast<Dali::CanvasRenderer::Shape&>(drawable);
+    Dali::CanvasRenderer::Gradient fillGradient = shape.GetFillGradient();
+    if(DALI_UNLIKELY(fillGradient))
+    {
+      Internal::Adaptor::Gradient& fillGradientImpl          = Dali::GetImplementation(fillGradient);
+      tvg::Fill*                   tvgDuplicatedFillGradient = static_cast<tvg::Fill*>(fillGradientImpl.GetObject())->duplicate();
+      if(!tvgDuplicatedFillGradient)
+      {
+        DALI_LOG_ERROR("Invalid gradient object [%p]\n", this);
+        return;
+      }
+      if(static_cast<tvg::Shape*>(tvgDuplicatedObject)->fill(std::unique_ptr<tvg::Fill>(tvgDuplicatedFillGradient)) != tvg::Result::Success)
+      {
+        DALI_LOG_ERROR("Tvg gradient set fail [%p]\n", this);
+        return;
+      }
+    }
+
+    //StrokeGradient
+    Dali::CanvasRenderer::Gradient strokeGradient = shape.GetStrokeGradient();
+    if(DALI_UNLIKELY(strokeGradient))
+    {
+      Internal::Adaptor::Gradient& strokeGradientImpl          = Dali::GetImplementation(strokeGradient);
+      tvg::Fill*                   tvgDuplicatedStrokeGradient = static_cast<tvg::Fill*>(strokeGradientImpl.GetObject())->duplicate();
+      if(!tvgDuplicatedStrokeGradient)
+      {
+        DALI_LOG_ERROR("Invalid gradient object [%p]\n", this);
+        return;
+      }
+      if(static_cast<tvg::Shape*>(tvgDuplicatedObject)->stroke(std::unique_ptr<tvg::Fill>(tvgDuplicatedStrokeGradient)) != tvg::Result::Success)
+      {
+        DALI_LOG_ERROR("Tvg gradient set fail [%p]\n", this);
+        return;
+      }
+    }
+  }
+
+  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(parent->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