[Tizen] CanvasRenderer: Set initial value of the viewBox to be same as Size.
[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     if(mViewBox == Vector2::ZERO)
411     {
412       mViewBox = size;
413     }
414     mChanged = true;
415   }
416
417   return true;
418 }
419
420 Vector2 CanvasRendererTizen::GetSize() const
421 {
422   return mSize;
423 }
424
425 bool CanvasRendererTizen::SetViewBox(const Vector2& viewBox)
426 {
427   if(viewBox.width < 1.0f || viewBox.height < 1.0f)
428   {
429     return false;
430   }
431
432   if(viewBox != mViewBox)
433   {
434     mViewBox = viewBox;
435     mChanged = true;
436   }
437
438   return true;
439 }
440
441 const Vector2& CanvasRendererTizen::GetViewBox()
442 {
443   return mViewBox;
444 }
445
446 void CanvasRendererTizen::MakeTargetBuffer(const Vector2& size)
447 {
448 #ifdef THORVG_SUPPORT
449   if(!mNativeImageQueue)
450   {
451     mNativeImageQueue = Dali::NativeImageSourceQueue::New(size.width, size.height, Dali::NativeImageSourceQueue::ColorFormat::RGBA8888);
452   }
453   else
454   {
455     mNativeImageQueue->SetSize(static_cast<uint32_t>(size.width), static_cast<uint32_t>(size.height));
456   }
457 #endif
458 }
459
460 #ifdef THORVG_SUPPORT
461 void CanvasRendererTizen::PushDrawableToGroup(Dali::CanvasRenderer::Drawable& drawable, tvg::Scene* parent)
462 {
463   Internal::Adaptor::Drawable& drawableImpl        = Dali::GetImplementation(drawable);
464   tvg::Paint*                  tvgDuplicatedObject = static_cast<tvg::Paint*>(drawableImpl.GetObject())->duplicate();
465   if(!tvgDuplicatedObject)
466   {
467     DALI_LOG_ERROR("Invalid drawable object [%p]\n", this);
468     return;
469   }
470   Drawable::Types type = drawableImpl.GetType();
471
472   if(type == Drawable::Types::DRAWABLE_GROUP)
473   {
474     Dali::CanvasRenderer::DrawableGroup& group             = static_cast<Dali::CanvasRenderer::DrawableGroup&>(drawable);
475     Internal::Adaptor::DrawableGroup&    drawableGroupImpl = Dali::GetImplementation(group);
476     DrawableGroup::DrawableVector        drawables         = drawableGroupImpl.GetDrawables();
477     for(auto& it : drawables)
478     {
479       PushDrawableToGroup(it, static_cast<tvg::Scene*>(tvgDuplicatedObject));
480     }
481   }
482   else if(type == Drawable::Types::SHAPE)
483   {
484     //FillGradient
485     Dali::CanvasRenderer::Shape&   shape        = static_cast<Dali::CanvasRenderer::Shape&>(drawable);
486     Dali::CanvasRenderer::Gradient fillGradient = shape.GetFillGradient();
487     if(DALI_UNLIKELY(fillGradient))
488     {
489       Internal::Adaptor::Gradient& fillGradientImpl          = Dali::GetImplementation(fillGradient);
490       tvg::Fill*                   tvgDuplicatedFillGradient = static_cast<tvg::Fill*>(fillGradientImpl.GetObject())->duplicate();
491       if(!tvgDuplicatedFillGradient)
492       {
493         DALI_LOG_ERROR("Invalid gradient object [%p]\n", this);
494         return;
495       }
496       if(static_cast<tvg::Shape*>(tvgDuplicatedObject)->fill(std::unique_ptr<tvg::Fill>(tvgDuplicatedFillGradient)) != tvg::Result::Success)
497       {
498         DALI_LOG_ERROR("Tvg gradient set fail [%p]\n", this);
499         return;
500       }
501     }
502
503     //StrokeGradient
504     Dali::CanvasRenderer::Gradient strokeGradient = shape.GetStrokeGradient();
505     if(DALI_UNLIKELY(strokeGradient))
506     {
507       Internal::Adaptor::Gradient& strokeGradientImpl          = Dali::GetImplementation(strokeGradient);
508       tvg::Fill*                   tvgDuplicatedStrokeGradient = static_cast<tvg::Fill*>(strokeGradientImpl.GetObject())->duplicate();
509       if(!tvgDuplicatedStrokeGradient)
510       {
511         DALI_LOG_ERROR("Invalid gradient object [%p]\n", this);
512         return;
513       }
514       if(static_cast<tvg::Shape*>(tvgDuplicatedObject)->stroke(std::unique_ptr<tvg::Fill>(tvgDuplicatedStrokeGradient)) != tvg::Result::Success)
515       {
516         DALI_LOG_ERROR("Tvg gradient set fail [%p]\n", this);
517         return;
518       }
519     }
520   }
521
522   Dali::CanvasRenderer::Drawable compositeDrawable = drawableImpl.GetCompositionDrawable();
523   if(DALI_UNLIKELY(compositeDrawable))
524   {
525     Internal::Adaptor::Drawable& compositeDrawableImpl = Dali::GetImplementation(compositeDrawable);
526     tvg::Paint*                  tvgCompositeObject    = static_cast<tvg::Paint*>(compositeDrawableImpl.GetObject());
527     if(tvgCompositeObject)
528     {
529       tvg::Paint*     tvgDuplicatedCompositeObject = tvgCompositeObject->duplicate();
530       Drawable::Types type                         = compositeDrawableImpl.GetType();
531
532       if(type == Drawable::Types::DRAWABLE_GROUP)
533       {
534         Dali::CanvasRenderer::DrawableGroup& compositeGroup             = static_cast<Dali::CanvasRenderer::DrawableGroup&>(compositeDrawable);
535         Internal::Adaptor::DrawableGroup&    compositeDrawableGroupImpl = Dali::GetImplementation(compositeGroup);
536         DrawableGroup::DrawableVector        compositeDrawables         = compositeDrawableGroupImpl.GetDrawables();
537         for(auto& it : compositeDrawables)
538         {
539           PushDrawableToGroup(it, static_cast<tvg::Scene*>(tvgDuplicatedCompositeObject));
540         }
541       }
542
543       if(tvgDuplicatedObject->composite(std::move(std::unique_ptr<tvg::Paint>(tvgDuplicatedCompositeObject)), static_cast<tvg::CompositeMethod>(drawableImpl.GetCompositionType())) != tvg::Result::Success)
544       {
545         DALI_LOG_ERROR("Tvg composite fail [%p]\n", this);
546         return;
547       }
548     }
549   }
550
551   if(parent->push(std::move(std::unique_ptr<tvg::Paint>(tvgDuplicatedObject))) != tvg::Result::Success)
552   {
553     DALI_LOG_ERROR("Tvg push fail [%p]\n", this);
554     return;
555   }
556 }
557 #endif
558
559 } // namespace Adaptor
560
561 } // namespace Internal
562
563 } // namespace Dali