[dali_2.3.25] Merge branch 'devel/master'
[platform/core/uifw/dali-adaptor.git] / dali / internal / vector-image / common / vector-image-renderer-impl.cpp
1 /*
2  * Copyright (c) 2023 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/vector-image/common/vector-image-renderer-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/object/type-registry.h>
24
25 #ifndef THORVG_SUPPORT
26 // INTERNAL INCLUDES
27 #include <third-party/nanosvg/nanosvg.h>
28 #include <third-party/nanosvg/nanosvgrast.h>
29 #endif
30
31 namespace Dali
32 {
33 namespace Internal
34 {
35 namespace Adaptor
36 {
37 namespace // unnamed namespace
38 {
39 const char* const UNITS("px");
40
41 // Type Registration
42 Dali::BaseHandle Create()
43 {
44   return Dali::BaseHandle();
45 }
46
47 Dali::TypeRegistration type(typeid(Dali::VectorImageRenderer), typeid(Dali::BaseHandle), Create);
48
49 #if defined(DEBUG_ENABLED)
50 Debug::Filter* gVectorImageLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_IMAGE");
51 #endif
52
53 } // unnamed namespace
54
55 VectorImageRendererPtr VectorImageRenderer::New()
56 {
57   VectorImageRendererPtr renderer = new VectorImageRenderer();
58   if(renderer)
59   {
60     renderer->Initialize();
61   }
62   return renderer;
63 }
64
65 VectorImageRenderer::VectorImageRenderer()
66 #ifdef THORVG_SUPPORT
67 : mPicture(nullptr)
68 #else
69 : mParsedImage(nullptr),
70   mRasterizer(nullptr)
71 #endif
72 {
73 }
74
75 VectorImageRenderer::~VectorImageRenderer()
76 {
77   Mutex::ScopedLock lock(mMutex);
78 #ifdef THORVG_SUPPORT
79
80   //NOTE: Initializer::term() will call clear() internally.
81   //However, due to the delete on mPicture, a crash occurs for the paint
82   //that has already been deleted in clear() of term().
83   //Therefore, it temporarily performs a non-free clear().
84   mSwCanvas->clear(false);
85
86   if(mPicture)
87   {
88     delete(mPicture);
89     mPicture = nullptr;
90   }
91
92   tvg::Initializer::term(tvg::CanvasEngine::Sw);
93 #else
94   if(mParsedImage)
95   {
96     nsvgDelete(mParsedImage);
97     mParsedImage = nullptr;
98   }
99
100   if(mRasterizer)
101   {
102     nsvgDeleteRasterizer(mRasterizer);
103     mRasterizer = nullptr;
104   }
105 #endif
106 }
107
108 void VectorImageRenderer::Initialize()
109 {
110 #ifdef THORVG_SUPPORT
111   tvg::Initializer::init(tvg::CanvasEngine::Sw, 0);
112
113   mSwCanvas = tvg::SwCanvas::gen();
114   mSwCanvas->mempool(tvg::SwCanvas::MempoolPolicy::Individual);
115   mSwCanvas->reserve(1); //has one picture
116 #else
117   mRasterizer = nsvgCreateRasterizer();
118 #endif
119 }
120
121 bool VectorImageRenderer::Load(const Vector<uint8_t>& data, float dpi)
122 {
123   Mutex::ScopedLock lock(mMutex);
124
125 #ifdef THORVG_SUPPORT
126   if(!mSwCanvas)
127   {
128     DALI_LOG_ERROR("VectorImageRenderer::Load Canvas Object is null [%p]\n", this);
129     return false;
130   }
131
132   if(!mPicture)
133   {
134     mPicture = tvg::Picture::gen().release();
135     if(!mPicture)
136     {
137       DALI_LOG_ERROR("VectorImageRenderer::Load: Picture gen Fail [%p]\n", this);
138       return false;
139     }
140   }
141   else
142   {
143     return true;
144   }
145
146   tvg::Result ret = mPicture->load(reinterpret_cast<char*>(data.Begin()), data.Size(), true);
147
148   if(ret != tvg::Result::Success)
149   {
150     switch(ret)
151     {
152       case tvg::Result::InvalidArguments:
153       {
154         DALI_LOG_ERROR("VectorImageRenderer::Load Load fail(Invalid arguments) Size:%d [%p]\n", data.Size(), this);
155         break;
156       }
157       case tvg::Result::NonSupport:
158       {
159         DALI_LOG_ERROR("VectorImageRenderer::Load Load fail(Invalid SVG) Size:%d [%p]\n", data.Size(), this);
160         break;
161       }
162       case tvg::Result::Unknown:
163       {
164         DALI_LOG_ERROR("VectorImageRenderer::Load Load fail(Parse fail) Size:%d [%p]\n", data.Size(), this);
165         break;
166       }
167       default:
168       {
169         DALI_LOG_ERROR("VectorImageRenderer::Load Load fail / Size:%d [%p]\n", data.Size(), this);
170         break;
171       }
172     }
173
174     // Destroy mPicture and make it as nullptr, so we can notify that we fail to load svg file.
175     if(mPicture)
176     {
177       delete(mPicture);
178       mPicture = nullptr;
179     }
180
181     return false;
182   }
183
184   float w, h;
185   mPicture->size(&w, &h);
186   mDefaultWidth  = static_cast<uint32_t>(w);
187   mDefaultHeight = static_cast<uint32_t>(h);
188
189   return true;
190 #else
191   if(mParsedImage)
192   {
193     return true;
194   }
195
196   mParsedImage = nsvgParse(reinterpret_cast<char*>(data.Begin()), UNITS, dpi);
197   if(!mParsedImage || !mParsedImage->shapes)
198   {
199     DALI_LOG_ERROR("VectorImageRenderer::Load: nsvgParse failed\n");
200
201     // Destroy mParsedImage and make it as nullptr, so we can notify that we fail to load svg file.
202     if(mParsedImage)
203     {
204       nsvgDelete(mParsedImage);
205       mParsedImage = nullptr;
206     }
207
208     return false;
209   }
210
211   mDefaultWidth  = mParsedImage->width;
212   mDefaultHeight = mParsedImage->height;
213
214   return true;
215 #endif
216 }
217
218 bool VectorImageRenderer::IsLoaded() const
219 {
220 #ifdef THORVG_SUPPORT
221   return mPicture ? true : false;
222 #else
223   return mParsedImage ? true : false;
224 #endif
225 }
226
227 Dali::Devel::PixelBuffer VectorImageRenderer::Rasterize(uint32_t width, uint32_t height)
228 {
229   Mutex::ScopedLock lock(mMutex);
230
231   if(width == 0)
232   {
233     if(mDefaultWidth == 0)
234     {
235       DALI_LOG_ERROR("Invalid size [%d, %d]\n", width, height);
236       return Devel::PixelBuffer();
237     }
238     else
239     {
240       width = mDefaultWidth;
241     }
242   }
243
244   if(height == 0)
245   {
246     if(mDefaultHeight == 0)
247     {
248       DALI_LOG_ERROR("Invalid size [%d, %d]\n", width, height);
249       return Devel::PixelBuffer();
250     }
251     else
252     {
253       height = mDefaultHeight;
254     }
255   }
256
257 #ifdef THORVG_SUPPORT
258   if(!mSwCanvas || !mPicture)
259   {
260     DALI_LOG_ERROR("VectorImageRenderer::Rasterize: either Canvas[%p] or Picture[%p] is invalid [%p]\n", mSwCanvas.get(), mPicture, this);
261     return Devel::PixelBuffer();
262   }
263
264   Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New(width, height, Dali::Pixel::RGBA8888);
265
266   mSwCanvas->clear(false);
267
268   auto pBuffer = pixelBuffer.GetBuffer();
269   if(!pBuffer)
270   {
271     DALI_LOG_ERROR("VectorImageRenderer::Rasterize: pixel buffer is null [%p]\n", this);
272     return Devel::PixelBuffer();
273   }
274
275   mSwCanvas->target(reinterpret_cast<uint32_t*>(pBuffer), width, width, height, tvg::SwCanvas::ABGR8888);
276
277   DALI_LOG_INFO(gVectorImageLogFilter, Debug::Verbose, "Buffer[%p] size[%d x %d]! [%p]\n", pBuffer, width, height, this);
278
279   mPicture->size(width, height);
280
281   /* We can push everytime since we cleared the canvas just before. */
282   if(mSwCanvas->push(std::unique_ptr<tvg::Picture>(mPicture)) != tvg::Result::Success)
283   {
284     DALI_LOG_ERROR("VectorImageRenderer::Rasterize: Picture push fail [%p]\n", this);
285     return Devel::PixelBuffer();
286   }
287
288   auto ret = mSwCanvas->draw();
289   if(ret != tvg::Result::Success)
290   {
291     DALI_LOG_ERROR("VectorImageRenderer::Rasterize: Draw fail %d [%p]\n", static_cast<int>(ret), this);
292     return Devel::PixelBuffer();
293   }
294
295   mSwCanvas->sync();
296
297   return pixelBuffer;
298 #else
299   if(mParsedImage != nullptr)
300   {
301     Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New(width, height, Dali::Pixel::RGBA8888);
302
303     float scaleX = static_cast<float>(width) / (mDefaultWidth > 0 ? static_cast<float>(mDefaultWidth) : 1.0f);
304     float scaleY = static_cast<float>(height) / (mDefaultHeight > 0 ? static_cast<float>(mDefaultHeight) : 1.0f);
305     float scale  = scaleX < scaleY ? scaleX : scaleY;
306     int   stride = pixelBuffer.GetWidth() * Pixel::GetBytesPerPixel(Dali::Pixel::RGBA8888);
307
308     nsvgRasterize(mRasterizer, mParsedImage, 0.0f, 0.0f, scale, pixelBuffer.GetBuffer(), width, height, stride);
309     return pixelBuffer;
310   }
311   return Devel::PixelBuffer();
312 #endif
313 }
314
315 void VectorImageRenderer::GetDefaultSize(uint32_t& width, uint32_t& height) const
316 {
317   width  = mDefaultWidth;
318   height = mDefaultHeight;
319 }
320
321 } // namespace Adaptor
322
323 } // namespace Internal
324
325 } // namespace Dali