e767ada99e0b5245a2fce7e261d2982f53b28ac4
[platform/core/uifw/dali-adaptor.git] / dali / internal / canvas-renderer / tizen / canvas-renderer-impl-tizen.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/canvas-renderer/tizen/canvas-renderer-impl-tizen.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/object/type-registry.h>
24
25 // INTERNAL INCLUDES
26 #include <dali/internal/canvas-renderer/common/drawable-group-impl.h>
27 #include <dali/internal/canvas-renderer/common/drawable-impl.h>
28 #include <dali/internal/canvas-renderer/common/gradient-impl.h>
29 #include <dali/internal/canvas-renderer/common/shape-impl.h>
30
31 namespace Dali
32 {
33 namespace Internal
34 {
35 namespace Adaptor
36 {
37 namespace // unnamed namespace
38 {
39 // Type Registration
40 Dali::BaseHandle Create()
41 {
42   return Dali::BaseHandle();
43 }
44
45 Dali::TypeRegistration type(typeid(Dali::CanvasRenderer), typeid(Dali::BaseHandle), Create);
46
47 } // unnamed namespace
48
49 CanvasRendererTizen* CanvasRendererTizen::New(const Vector2& viewBox)
50 {
51   return new CanvasRendererTizen(viewBox);
52 }
53
54 CanvasRendererTizen::CanvasRendererTizen(const Vector2& viewBox)
55 :
56 #ifdef THORVG_SUPPORT
57   mRasterizedTexture(),
58   mMutex(),
59   mTvgCanvas(nullptr),
60   mTvgRoot(nullptr),
61   mNativeImageQueue(nullptr),
62 #endif
63   mSize(Vector2::ZERO),
64   mViewBox(Vector2::ZERO),
65   mChanged(false)
66 {
67   Initialize(viewBox);
68 }
69
70 CanvasRendererTizen::~CanvasRendererTizen()
71 {
72 #ifdef THORVG_SUPPORT
73   mDrawables.clear();
74
75   //Terminate ThorVG Engine
76   tvg::Initializer::term(tvg::CanvasEngine::Sw);
77 #endif
78 }
79
80 void CanvasRendererTizen::Initialize(const Vector2& viewBox)
81 {
82 #ifdef THORVG_SUPPORT
83   if(tvg::Initializer::init(tvg::CanvasEngine::Sw, 0 /*threads*/) != tvg::Result::Success)
84   {
85     DALI_LOG_ERROR("ThorVG engine initialize failed\n");
86   }
87   mTvgCanvas = tvg::SwCanvas::gen();
88
89   mSize = mViewBox = viewBox;
90   if(viewBox.width < 1.0f || viewBox.height < 1.0f)
91   {
92     return;
93   }
94
95   MakeTargetBuffer(mSize);
96 #endif
97 }
98
99 bool CanvasRendererTizen::Commit()
100 {
101 #ifdef THORVG_SUPPORT
102   Mutex::ScopedLock lock(mMutex);
103
104   if(mSize.width < 1.0f || mSize.height < 1.0f)
105   {
106     DALI_LOG_ERROR("Size is zero [%p]\n", this);
107     return false;
108   }
109
110   bool changed = false;
111
112   for(auto& it : mDrawables)
113   {
114     if(HaveDrawablesChanged(it))
115     {
116       UpdateDrawablesChanged(it, false);
117       changed = true;
118     }
119   }
120
121   if(!changed && !mChanged)
122   {
123     return false;
124   }
125   else
126   {
127     MakeTargetBuffer(mSize);
128     mChanged = false;
129   }
130
131   if(mTvgCanvas->clear() != tvg::Result::Success)
132   {
133     DALI_LOG_ERROR("ThorVG canvas clear fail [%p]\n", this);
134     return false;
135   }
136
137   auto scene = tvg::Scene::gen();
138   mTvgRoot   = scene.get();
139   for(auto& it : mDrawables)
140   {
141     PushDrawableToGroup(it, mTvgRoot);
142   }
143
144   if(mViewBox != mSize && mViewBox.width > 0 && mViewBox.height > 0)
145   {
146     auto scaleX = mSize.width / mViewBox.width;
147     auto scaleY = mSize.height / mViewBox.height;
148     mTvgRoot->scale(scaleX < scaleY ? scaleX : scaleY);
149   }
150
151   if(mTvgCanvas->push(move(scene)) != tvg::Result::Success)
152   {
153     DALI_LOG_ERROR("ThorVG canvas push fail [%p]\n", this);
154     return false;
155   }
156
157   return true;
158 #else
159   return false;
160 #endif
161 }
162
163 Dali::Texture CanvasRendererTizen::GetRasterizedTexture()
164 {
165 #ifdef THORVG_SUPPORT
166   if(mNativeImageQueue)
167   {
168     if(!mRasterizedTexture)
169     {
170       mRasterizedTexture = Dali::Texture::New(*mNativeImageQueue);
171     }
172     return mRasterizedTexture;
173   }
174   else
175   {
176     return Dali::Texture();
177   }
178 #else
179   return Dali::Texture();
180 #endif
181 }
182
183 bool CanvasRendererTizen::AddDrawable(Dali::CanvasRenderer::Drawable& drawable)
184 {
185 #ifdef THORVG_SUPPORT
186   Internal::Adaptor::Drawable& drawableImpl = GetImplementation(drawable);
187   if(drawableImpl.IsAdded())
188   {
189     DALI_LOG_ERROR("Already added [%p][%p]\n", this, &drawable);
190     return false;
191   }
192
193   drawableImpl.SetAdded(true);
194   mDrawables.push_back(drawable);
195   mChanged = true;
196
197   return true;
198 #else
199   return false;
200 #endif
201 }
202
203 #ifdef THORVG_SUPPORT
204 bool CanvasRendererTizen::HaveDrawablesChanged(const Dali::CanvasRenderer::Drawable& drawable) const
205 {
206   const Internal::Adaptor::Drawable& drawableImpl = GetImplementation(drawable);
207   if(drawableImpl.GetChanged())
208   {
209     return true;
210   }
211   Dali::CanvasRenderer::Drawable compositeDrawable = drawableImpl.GetCompositionDrawable();
212   if(DALI_UNLIKELY(compositeDrawable))
213   {
214     Internal::Adaptor::Drawable& compositeDrawableImpl = Dali::GetImplementation(compositeDrawable);
215     if(compositeDrawableImpl.GetChanged())
216     {
217       return true;
218     }
219   }
220
221   if(drawableImpl.GetType() == Drawable::Types::DRAWABLE_GROUP)
222   {
223     const Dali::CanvasRenderer::DrawableGroup& group             = static_cast<const Dali::CanvasRenderer::DrawableGroup&>(drawable);
224     const Internal::Adaptor::DrawableGroup&    drawableGroupImpl = Dali::GetImplementation(group);
225     DrawableGroup::DrawableVector              drawables         = drawableGroupImpl.GetDrawables();
226     for(auto& it : drawables)
227     {
228       if(HaveDrawablesChanged(it))
229       {
230         return true;
231       }
232     }
233   }
234   else if(drawableImpl.GetType() == Drawable::Types::SHAPE)
235   {
236     const Dali::CanvasRenderer::Shape& shape        = static_cast<const Dali::CanvasRenderer::Shape&>(drawable);
237     Dali::CanvasRenderer::Gradient     fillGradient = shape.GetFillGradient();
238     if(DALI_UNLIKELY(fillGradient))
239     {
240       Internal::Adaptor::Gradient& fillGradientImpl = Dali::GetImplementation(fillGradient);
241       if(fillGradientImpl.GetChanged())
242       {
243         return true;
244       }
245     }
246
247     Dali::CanvasRenderer::Gradient strokeGradient = shape.GetStrokeGradient();
248     if(DALI_UNLIKELY(strokeGradient))
249     {
250       Internal::Adaptor::Gradient& strokeGradientImpl = Dali::GetImplementation(strokeGradient);
251       if(strokeGradientImpl.GetChanged())
252       {
253         return true;
254       }
255     }
256   }
257
258   return false;
259 }
260
261 void CanvasRendererTizen::UpdateDrawablesChanged(Dali::CanvasRenderer::Drawable& drawable, bool changed)
262 {
263   Internal::Adaptor::Drawable& drawableImpl = GetImplementation(drawable);
264   drawableImpl.SetChanged(changed);
265
266   Dali::CanvasRenderer::Drawable compositeDrawable = drawableImpl.GetCompositionDrawable();
267   if(DALI_UNLIKELY(compositeDrawable))
268   {
269     Internal::Adaptor::Drawable& compositeDrawableImpl = Dali::GetImplementation(compositeDrawable);
270     compositeDrawableImpl.SetChanged(changed);
271   }
272
273   if(drawableImpl.GetType() == Drawable::Types::DRAWABLE_GROUP)
274   {
275     Dali::CanvasRenderer::DrawableGroup& group             = static_cast<Dali::CanvasRenderer::DrawableGroup&>(drawable);
276     Internal::Adaptor::DrawableGroup&    drawableGroupImpl = Dali::GetImplementation(group);
277     DrawableGroup::DrawableVector        drawables         = drawableGroupImpl.GetDrawables();
278     for(auto& it : drawables)
279     {
280       UpdateDrawablesChanged(it, changed);
281     }
282   }
283   else if(drawableImpl.GetType() == Drawable::Types::SHAPE)
284   {
285     Dali::CanvasRenderer::Shape&   shape        = static_cast<Dali::CanvasRenderer::Shape&>(drawable);
286     Dali::CanvasRenderer::Gradient fillGradient = shape.GetFillGradient();
287     if(DALI_UNLIKELY(fillGradient))
288     {
289       Internal::Adaptor::Gradient& fillGradientImpl = Dali::GetImplementation(fillGradient);
290       fillGradientImpl.SetChanged(changed);
291     }
292
293     Dali::CanvasRenderer::Gradient strokeGradient = shape.GetStrokeGradient();
294     if(DALI_UNLIKELY(strokeGradient))
295     {
296       Internal::Adaptor::Gradient& strokeGradientImpl = Dali::GetImplementation(strokeGradient);
297       strokeGradientImpl.SetChanged(changed);
298     }
299   }
300 }
301 #endif
302
303 bool CanvasRendererTizen::IsCanvasChanged() const
304 {
305 #ifdef THORVG_SUPPORT
306   if(mChanged)
307   {
308     return true;
309   }
310
311   for(auto& it : mDrawables)
312   {
313     if(HaveDrawablesChanged(it))
314     {
315       return true;
316     }
317   }
318 #endif
319   return false;
320 }
321
322 bool CanvasRendererTizen::Rasterize()
323 {
324 #ifdef THORVG_SUPPORT
325   Mutex::ScopedLock lock(mMutex);
326
327   if(mNativeImageQueue && mNativeImageQueue->CanDequeueBuffer())
328   {
329     uint32_t width, height, stride;
330     uint8_t* buffer = mNativeImageQueue->DequeueBuffer(width, height, stride);
331     if(!buffer)
332     {
333       DALI_LOG_ERROR("Pixel buffer create to fail [%p]\n", this);
334       return false;
335     }
336
337     mTvgCanvas->target(reinterpret_cast<uint32_t*>(buffer), stride / 4, width, height, tvg::SwCanvas::ARGB8888);
338
339     mTvgCanvas->update(mTvgRoot);
340
341     if(mTvgCanvas->draw() != tvg::Result::Success)
342     {
343       DALI_LOG_ERROR("ThorVG Draw fail [%p]\n", this);
344       mNativeImageQueue->EnqueueBuffer(buffer);
345       return false;
346     }
347
348     mTvgCanvas->sync();
349
350     mNativeImageQueue->EnqueueBuffer(buffer);
351   }
352   else
353   {
354     return false;
355   }
356
357   return true;
358 #else
359   return false;
360 #endif
361 }
362
363 bool CanvasRendererTizen::RemoveDrawable(Dali::CanvasRenderer::Drawable& drawable)
364 {
365 #ifdef THORVG_SUPPORT
366   DrawableGroup::DrawableVector::iterator it = std::find(mDrawables.begin(), mDrawables.end(), drawable);
367   if(it != mDrawables.end())
368   {
369     Internal::Adaptor::Drawable& drawableImpl = GetImplementation(drawable);
370     drawableImpl.SetAdded(false);
371
372     mDrawables.erase(it);
373     mChanged = true;
374
375     return true;
376   }
377
378 #endif
379   return false;
380 }
381
382 bool CanvasRendererTizen::RemoveAllDrawables()
383 {
384 #ifdef THORVG_SUPPORT
385   for(auto& it : mDrawables)
386   {
387     Internal::Adaptor::Drawable& drawableImpl = GetImplementation(it);
388     drawableImpl.SetAdded(false);
389   }
390
391   mDrawables.clear();
392   mChanged = true;
393
394   return true;
395 #else
396   return false;
397 #endif
398 }
399
400 bool CanvasRendererTizen::SetSize(Vector2 size)
401 {
402   if(size.width < 1.0f || size.height < 1.0f)
403   {
404     return false;
405   }
406
407   if(size != mSize)
408   {
409     mSize    = size;
410     mChanged = true;
411   }
412
413   return true;
414 }
415
416 Vector2 CanvasRendererTizen::GetSize() const
417 {
418   return mSize;
419 }
420
421 bool CanvasRendererTizen::SetViewBox(const Vector2& viewBox)
422 {
423   if(viewBox.width < 1.0f || viewBox.height < 1.0f)
424   {
425     return false;
426   }
427
428   if(viewBox != mViewBox)
429   {
430     mViewBox = viewBox;
431     mChanged = true;
432   }
433
434   return true;
435 }
436
437 const Vector2& CanvasRendererTizen::GetViewBox()
438 {
439   return mViewBox;
440 }
441
442 void CanvasRendererTizen::MakeTargetBuffer(const Vector2& size)
443 {
444 #ifdef THORVG_SUPPORT
445   if(!mNativeImageQueue)
446   {
447     mNativeImageQueue = Dali::NativeImageSourceQueue::New(size.width, size.height, Dali::NativeImageSourceQueue::ColorFormat::RGBA8888);
448   }
449   else
450   {
451     mNativeImageQueue->SetSize(static_cast<uint32_t>(size.width), static_cast<uint32_t>(size.height));
452   }
453 #endif
454 }
455
456 #ifdef THORVG_SUPPORT
457 void CanvasRendererTizen::PushDrawableToGroup(Dali::CanvasRenderer::Drawable& drawable, tvg::Scene* parent)
458 {
459   Internal::Adaptor::Drawable& drawableImpl        = Dali::GetImplementation(drawable);
460   tvg::Paint*                  tvgDuplicatedObject = static_cast<tvg::Paint*>(drawableImpl.GetObject())->duplicate();
461   if(!tvgDuplicatedObject)
462   {
463     DALI_LOG_ERROR("Invalid drawable object [%p]\n", this);
464     return;
465   }
466   Drawable::Types type = drawableImpl.GetType();
467
468   if(type == Drawable::Types::DRAWABLE_GROUP)
469   {
470     Dali::CanvasRenderer::DrawableGroup& group             = static_cast<Dali::CanvasRenderer::DrawableGroup&>(drawable);
471     Internal::Adaptor::DrawableGroup&    drawableGroupImpl = Dali::GetImplementation(group);
472     DrawableGroup::DrawableVector        drawables         = drawableGroupImpl.GetDrawables();
473     for(auto& it : drawables)
474     {
475       PushDrawableToGroup(it, static_cast<tvg::Scene*>(tvgDuplicatedObject));
476     }
477   }
478   else if(type == Drawable::Types::SHAPE)
479   {
480     //FillGradient
481     Dali::CanvasRenderer::Shape&   shape        = static_cast<Dali::CanvasRenderer::Shape&>(drawable);
482     Dali::CanvasRenderer::Gradient fillGradient = shape.GetFillGradient();
483     if(DALI_UNLIKELY(fillGradient))
484     {
485       Internal::Adaptor::Gradient& fillGradientImpl          = Dali::GetImplementation(fillGradient);
486       tvg::Fill*                   tvgDuplicatedFillGradient = static_cast<tvg::Fill*>(fillGradientImpl.GetObject())->duplicate();
487       if(!tvgDuplicatedFillGradient)
488       {
489         DALI_LOG_ERROR("Invalid gradient object [%p]\n", this);
490         return;
491       }
492       if(static_cast<tvg::Shape*>(tvgDuplicatedObject)->fill(std::unique_ptr<tvg::Fill>(tvgDuplicatedFillGradient)) != tvg::Result::Success)
493       {
494         DALI_LOG_ERROR("Tvg gradient set fail [%p]\n", this);
495         return;
496       }
497     }
498
499     //StrokeGradient
500     Dali::CanvasRenderer::Gradient strokeGradient = shape.GetStrokeGradient();
501     if(DALI_UNLIKELY(strokeGradient))
502     {
503       Internal::Adaptor::Gradient& strokeGradientImpl          = Dali::GetImplementation(strokeGradient);
504       tvg::Fill*                   tvgDuplicatedStrokeGradient = static_cast<tvg::Fill*>(strokeGradientImpl.GetObject())->duplicate();
505       if(!tvgDuplicatedStrokeGradient)
506       {
507         DALI_LOG_ERROR("Invalid gradient object [%p]\n", this);
508         return;
509       }
510       if(static_cast<tvg::Shape*>(tvgDuplicatedObject)->stroke(std::unique_ptr<tvg::Fill>(tvgDuplicatedStrokeGradient)) != tvg::Result::Success)
511       {
512         DALI_LOG_ERROR("Tvg gradient set fail [%p]\n", this);
513         return;
514       }
515     }
516   }
517
518   Dali::CanvasRenderer::Drawable compositeDrawable = drawableImpl.GetCompositionDrawable();
519   if(DALI_UNLIKELY(compositeDrawable))
520   {
521     Internal::Adaptor::Drawable& compositeDrawableImpl = Dali::GetImplementation(compositeDrawable);
522     tvg::Paint*                  tvgCompositeObject    = static_cast<tvg::Paint*>(compositeDrawableImpl.GetObject());
523     if(tvgCompositeObject)
524     {
525       tvg::Paint*     tvgDuplicatedCompositeObject = tvgCompositeObject->duplicate();
526       Drawable::Types type                         = compositeDrawableImpl.GetType();
527
528       if(type == Drawable::Types::DRAWABLE_GROUP)
529       {
530         Dali::CanvasRenderer::DrawableGroup& compositeGroup             = static_cast<Dali::CanvasRenderer::DrawableGroup&>(compositeDrawable);
531         Internal::Adaptor::DrawableGroup&    compositeDrawableGroupImpl = Dali::GetImplementation(compositeGroup);
532         DrawableGroup::DrawableVector        compositeDrawables         = compositeDrawableGroupImpl.GetDrawables();
533         for(auto& it : compositeDrawables)
534         {
535           PushDrawableToGroup(it, static_cast<tvg::Scene*>(tvgDuplicatedCompositeObject));
536         }
537       }
538
539       if(tvgDuplicatedObject->composite(std::move(std::unique_ptr<tvg::Paint>(tvgDuplicatedCompositeObject)), static_cast<tvg::CompositeMethod>(drawableImpl.GetCompositionType())) != tvg::Result::Success)
540       {
541         DALI_LOG_ERROR("Tvg composite fail [%p]\n", this);
542         return;
543       }
544     }
545   }
546
547   if(parent->push(std::move(std::unique_ptr<tvg::Paint>(tvgDuplicatedObject))) != tvg::Result::Success)
548   {
549     DALI_LOG_ERROR("Tvg push fail [%p]\n", this);
550     return;
551   }
552 }
553 #endif
554
555 } // namespace Adaptor
556
557 } // namespace Internal
558
559 } // namespace Dali