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