// 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
}
CanvasRendererUbuntu::CanvasRendererUbuntu(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);
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
}
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);
}
}
}
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;
}
- mTvgCanvas->sync();
-
return true;
#else
return false;
#endif
}
-Devel::PixelBuffer CanvasRendererUbuntu::GetPixelBuffer()
+Dali::Texture CanvasRendererUbuntu::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 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;
+ }
+ Dali::CanvasRenderer::Drawable compositeDrawable = drawableImpl.GetCompositionDrawable();
+ if(DALI_UNLIKELY(compositeDrawable))
+ {
+ 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 CanvasRendererUbuntu::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);
+ }
+
+ Dali::CanvasRenderer::Gradient strokeGradient = shape.GetStrokeGradient();
+ if(DALI_UNLIKELY(strokeGradient))
+ {
+ Internal::Adaptor::Gradient& strokeGradientImpl = Dali::GetImplementation(strokeGradient);
+ strokeGradientImpl.SetChanged(changed);
+ }
+ }
+}
+#endif
+
+bool CanvasRendererUbuntu::IsCanvasChanged() const
+{
+#ifdef THORVG_SUPPORT
+ if(mChanged)
+ {
+ return true;
}
- if(mTvgRoot->push(std::unique_ptr<tvg::Paint>(pDrawable)) != tvg::Result::Success)
+ for(auto& it : mDrawables)
{
- DALI_LOG_ERROR("Tvg push fail [%p]\n", this);
+ if(HaveDrawablesChanged(it))
+ {
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+
+bool CanvasRendererUbuntu::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 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::RemoveAllDrawables()
+{
+#ifdef THORVG_SUPPORT
+ for(auto& it : mDrawables)
+ {
+ Internal::Adaptor::Drawable& drawableImpl = GetImplementation(it);
+ drawableImpl.SetAdded(false);
+ }
+
+ mDrawables.clear();
mChanged = true;
return true;
#endif
}
-bool CanvasRendererUbuntu::SetSize(const Vector2& size)
+bool CanvasRendererUbuntu::SetSize(Vector2 size)
{
if(size.width < 1.0f || size.height < 1.0f)
{
if(size != mSize)
{
- mSize = size;
- MakeTargetBuffer(size);
+ mSize = size;
+ mChanged = true;
}
- mChanged = true;
-
return true;
}
-const Vector2& CanvasRendererUbuntu::GetSize()
+Vector2 CanvasRendererUbuntu::GetSize() const
{
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
- 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();
return;
}
- 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 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));
+ }
+ }
+ 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(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