Merge branch 'devel/master' into tizen
[platform/core/uifw/dali-adaptor.git] / dali / internal / vector-image / common / vector-image-renderer-impl.cpp
index 858201e..feb8b5a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/object/type-registry.h>
 
+#ifndef THORVG_SUPPORT
 // INTERNAL INCLUDES
 #include <third-party/nanosvg/nanosvg.h>
 #include <third-party/nanosvg/nanosvgrast.h>
+#endif
 
 namespace Dali
 {
@@ -44,6 +46,10 @@ Dali::BaseHandle Create()
 
 Dali::TypeRegistration type(typeid(Dali::VectorImageRenderer), typeid(Dali::BaseHandle), Create);
 
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gVectorImageLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_IMAGE");
+#endif
+
 } // unnamed namespace
 
 VectorImageRendererPtr VectorImageRenderer::New()
@@ -57,14 +63,32 @@ VectorImageRendererPtr VectorImageRenderer::New()
 }
 
 VectorImageRenderer::VectorImageRenderer()
-: mPlugin(std::string()),
-  mParsedImage(nullptr),
+#ifdef THORVG_SUPPORT
+: mPicture(nullptr)
+#else
+: mParsedImage(nullptr),
   mRasterizer(nullptr)
+#endif
 {
 }
 
 VectorImageRenderer::~VectorImageRenderer()
 {
+#ifdef THORVG_SUPPORT
+
+  //NOTE: Initializer::term() will call clear() internally.
+  //However, due to the delete on mPicture, a crash occurs for the paint
+  //that has already been deleted in clear() of term().
+  //Therefore, it temporarily performs a non-free clear().
+  mSwCanvas->clear(false);
+
+  if(mPicture)
+  {
+    delete(mPicture);
+  }
+
+  tvg::Initializer::term(tvg::CanvasEngine::Sw);
+#else
   if(mParsedImage)
   {
     nsvgDelete(mParsedImage);
@@ -74,66 +98,200 @@ VectorImageRenderer::~VectorImageRenderer()
   {
     nsvgDeleteRasterizer(mRasterizer);
   }
+#endif
 }
 
 void VectorImageRenderer::Initialize()
 {
-  if(!mPlugin.IsValid())
-  {
-    mRasterizer = nsvgCreateRasterizer();
-  }
+#ifdef THORVG_SUPPORT
+  tvg::Initializer::init(tvg::CanvasEngine::Sw, 0);
+
+  mSwCanvas = tvg::SwCanvas::gen();
+  mSwCanvas->mempool(tvg::SwCanvas::MempoolPolicy::Individual);
+  mSwCanvas->reserve(1); //has one picture
+#else
+  mRasterizer = nsvgCreateRasterizer();
+#endif
 }
 
 bool VectorImageRenderer::Load(const Vector<uint8_t>& data, float dpi)
 {
-  if(mPlugin.IsValid())
+#ifdef THORVG_SUPPORT
+  if(!mSwCanvas)
   {
-    return mPlugin.Load(data);
+    DALI_LOG_ERROR("VectorImageRenderer::Load Canvas Object is null [%p]\n", this);
+    return false;
   }
-  else
+
+  if(!mPicture)
   {
-    mParsedImage = nsvgParse(reinterpret_cast<char*>(data.Begin()), UNITS, dpi);
-    if(!mParsedImage || !mParsedImage->shapes)
+    mPicture = tvg::Picture::gen().release();
+    if(!mPicture)
     {
-      DALI_LOG_ERROR("VectorImageRenderer::Load: nsvgParse failed\n");
+      DALI_LOG_ERROR("VectorImageRenderer::Load: Picture gen Fail [%p]\n", this);
       return false;
     }
-    return true;
   }
-}
-
-bool VectorImageRenderer::Rasterize(Dali::Devel::PixelBuffer& buffer, float scale)
-{
-  if(mPlugin.IsValid())
+  else
   {
-    return mPlugin.Rasterize(buffer);
+    return true;
   }
-  else
+
+  tvg::Result ret = mPicture->load(reinterpret_cast<char*>(data.Begin()), data.Size(), true);
+
+  if(ret != tvg::Result::Success)
   {
-    if(mParsedImage != nullptr)
+    switch(ret)
     {
-      int stride = buffer.GetWidth() * Pixel::GetBytesPerPixel(buffer.GetPixelFormat());
-      nsvgRasterize(mRasterizer, mParsedImage, 0.0f, 0.0f, scale, buffer.GetBuffer(), buffer.GetWidth(), buffer.GetHeight(), stride);
-      return true;
+      case tvg::Result::InvalidArguments:
+      {
+        DALI_LOG_ERROR("VectorImageRenderer::Load Load fail(Invalid arguments) Size:%d [%p]\n", data.Size(), this);
+        break;
+      }
+      case tvg::Result::NonSupport:
+      {
+        DALI_LOG_ERROR("VectorImageRenderer::Load Load fail(Invalid SVG) Size:%d [%p]\n", data.Size(), this);
+        break;
+      }
+      case tvg::Result::Unknown:
+      {
+        DALI_LOG_ERROR("VectorImageRenderer::Load Load fail(Parse fail) Size:%d [%p]\n", data.Size(), this);
+        break;
+      }
+      default:
+      {
+        DALI_LOG_ERROR("VectorImageRenderer::Load Load fail / Size:%d [%p]\n", data.Size(), this);
+        break;
+      }
     }
     return false;
   }
+
+  float w, h;
+  mPicture->size(&w, &h);
+  mDefaultWidth  = static_cast<uint32_t>(w);
+  mDefaultHeight = static_cast<uint32_t>(h);
+
+  return true;
+#else
+  if(mParsedImage)
+  {
+    return true;
+  }
+
+  mParsedImage = nsvgParse(reinterpret_cast<char*>(data.Begin()), UNITS, dpi);
+  if(!mParsedImage || !mParsedImage->shapes)
+  {
+    DALI_LOG_ERROR("VectorImageRenderer::Load: nsvgParse failed\n");
+    return false;
+  }
+
+  mDefaultWidth  = mParsedImage->width;
+  mDefaultHeight = mParsedImage->height;
+
+  return true;
+#endif
 }
 
-void VectorImageRenderer::GetDefaultSize(uint32_t& width, uint32_t& height) const
+bool VectorImageRenderer::IsLoaded() const
+{
+#ifdef THORVG_SUPPORT
+  return mPicture ? true : false;
+#else
+  return mParsedImage ? true : false;
+#endif
+}
+
+Dali::Devel::PixelBuffer VectorImageRenderer::Rasterize(uint32_t width, uint32_t height)
 {
-  if(mPlugin.IsValid())
+  if(width == 0)
   {
-    mPlugin.GetDefaultSize(width, height);
+    if(mDefaultWidth == 0)
+    {
+      DALI_LOG_ERROR("Invalid size [%d, %d]\n", width, height);
+      return Devel::PixelBuffer();
+    }
+    else
+    {
+      width = mDefaultWidth;
+    }
   }
-  else
+
+  if(height == 0)
   {
-    if(mParsedImage)
+    if(mDefaultHeight == 0)
+    {
+      DALI_LOG_ERROR("Invalid size [%d, %d]\n", width, height);
+      return Devel::PixelBuffer();
+    }
+    else
     {
-      width  = mParsedImage->width;
-      height = mParsedImage->height;
+      height = mDefaultHeight;
     }
   }
+
+#ifdef THORVG_SUPPORT
+  if(!mSwCanvas || !mPicture)
+  {
+    DALI_LOG_ERROR("VectorImageRenderer::Rasterize: either Canvas[%p] or Picture[%p] is invalid [%p]\n", mSwCanvas.get(), mPicture, this);
+    return Devel::PixelBuffer();
+  }
+
+  Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New(width, height, Dali::Pixel::RGBA8888);
+
+  mSwCanvas->clear(false);
+
+  auto pBuffer = pixelBuffer.GetBuffer();
+  if(!pBuffer)
+  {
+    DALI_LOG_ERROR("VectorImageRenderer::Rasterize: pixel buffer is null [%p]\n", this);
+    return Devel::PixelBuffer();
+  }
+
+  mSwCanvas->target(reinterpret_cast<uint32_t*>(pBuffer), width, width, height, tvg::SwCanvas::ABGR8888);
+
+  DALI_LOG_INFO(gVectorImageLogFilter, Debug::Verbose, "Buffer[%p] size[%d x %d]! [%p]\n", pBuffer, width, height, this);
+
+  mPicture->size(width, height);
+
+  /* We can push everytime since we cleared the canvas just before. */
+  if(mSwCanvas->push(std::unique_ptr<tvg::Picture>(mPicture)) != tvg::Result::Success)
+  {
+    DALI_LOG_ERROR("VectorImageRenderer::Rasterize: Picture push fail [%p]\n", this);
+    return Devel::PixelBuffer();
+  }
+
+  auto ret = mSwCanvas->draw();
+  if(ret != tvg::Result::Success)
+  {
+    DALI_LOG_ERROR("VectorImageRenderer::Rasterize: Draw fail %d [%p]\n", static_cast<int>(ret), this);
+    return Devel::PixelBuffer();
+  }
+
+  mSwCanvas->sync();
+
+  return pixelBuffer;
+#else
+  if(mParsedImage != nullptr)
+  {
+    Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New(width, height, Dali::Pixel::RGBA8888);
+
+    float scaleX = static_cast<float>(width) / (mDefaultWidth > 0 ? static_cast<float>(mDefaultWidth) : 1.0f);
+    float scaleY = static_cast<float>(height) / (mDefaultHeight > 0 ? static_cast<float>(mDefaultHeight) : 1.0f);
+    float scale  = scaleX < scaleY ? scaleX : scaleY;
+    int   stride = pixelBuffer.GetWidth() * Pixel::GetBytesPerPixel(Dali::Pixel::RGBA8888);
+
+    nsvgRasterize(mRasterizer, mParsedImage, 0.0f, 0.0f, scale, pixelBuffer.GetBuffer(), width, height, stride);
+    return pixelBuffer;
+  }
+  return Devel::PixelBuffer();
+#endif
+}
+
+void VectorImageRenderer::GetDefaultSize(uint32_t& width, uint32_t& height) const
+{
+  width  = mDefaultWidth;
+  height = mDefaultHeight;
 }
 
 } // namespace Adaptor