[Tizen] VectorImageRenderer: Fix data released in case of async loading
[platform/core/uifw/dali-adaptor.git] / dali / internal / vector-image / common / vector-image-renderer-impl.cpp
1 /*
2  * Copyright (c) 2022 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 } // unnamed namespace
50
51 VectorImageRendererPtr VectorImageRenderer::New()
52 {
53   VectorImageRendererPtr renderer = new VectorImageRenderer();
54   if(renderer)
55   {
56     renderer->Initialize();
57   }
58   return renderer;
59 }
60
61 VectorImageRenderer::VectorImageRenderer()
62 #ifdef THORVG_SUPPORT
63 : mPicture(nullptr),
64   mDefaultWidth(0),
65   mDefaultHeight(0)
66 #else
67 : mParsedImage(nullptr),
68   mRasterizer(nullptr)
69 #endif
70 {
71 }
72
73 VectorImageRenderer::~VectorImageRenderer()
74 {
75 #ifdef THORVG_SUPPORT
76
77   //NOTE: Initializer::term() will call clear() internally.
78   //However, due to the delete on mPicture, a crash occurs for the paint
79   //that has already been deleted in clear() of term().
80   //Therefore, it temporarily performs a non-free clear().
81   mSwCanvas->clear(false);
82
83   if(mPicture)
84   {
85     delete(mPicture);
86   }
87
88   tvg::Initializer::term(tvg::CanvasEngine::Sw);
89 #else
90   if(mParsedImage)
91   {
92     nsvgDelete(mParsedImage);
93   }
94
95   if(mRasterizer)
96   {
97     nsvgDeleteRasterizer(mRasterizer);
98   }
99 #endif
100 }
101
102 void VectorImageRenderer::Initialize()
103 {
104 #ifdef THORVG_SUPPORT
105   tvg::Initializer::init(tvg::CanvasEngine::Sw, 0);
106
107   mSwCanvas = tvg::SwCanvas::gen();
108   mSwCanvas->mempool(tvg::SwCanvas::MempoolPolicy::Individual);
109   mSwCanvas->reserve(1); //has one picture
110 #else
111   mRasterizer  = nsvgCreateRasterizer();
112 #endif
113 }
114
115 bool VectorImageRenderer::Load(const Vector<uint8_t>& data, float dpi)
116 {
117 #ifdef THORVG_SUPPORT
118   if(!mSwCanvas)
119   {
120     DALI_LOG_ERROR("VectorImageRenderer::Load Canvas Object is null [%p]\n", this);
121     return false;
122   }
123
124   if(!mPicture)
125   {
126     mPicture = tvg::Picture::gen().release();
127     if(!mPicture)
128     {
129       DALI_LOG_ERROR("VectorImageRenderer::Load: Picture gen Fail [%p]\n", this);
130       return false;
131     }
132   }
133
134   tvg::Result ret = mPicture->load(reinterpret_cast<char*>(data.Begin()), data.Size(), true);
135
136   if(ret != tvg::Result::Success)
137   {
138     switch(ret)
139     {
140       case tvg::Result::InvalidArguments:
141       {
142         DALI_LOG_ERROR("VectorImageRenderer::Load Load fail(Invalid arguments) Size:%d [%p]\n", data.Size(), this);
143         break;
144       }
145       case tvg::Result::NonSupport:
146       {
147         DALI_LOG_ERROR("VectorImageRenderer::Load Load fail(Invalid SVG) Size:%d [%p]\n", data.Size(), this);
148         break;
149       }
150       case tvg::Result::Unknown:
151       {
152         DALI_LOG_ERROR("VectorImageRenderer::Load Load fail(Parse fail) Size:%d [%p]\n", data.Size(), this);
153         break;
154       }
155       default:
156       {
157         DALI_LOG_ERROR("VectorImageRenderer::Load Load fail / Size:%d [%p]\n", data.Size(), this);
158         break;
159       }
160     }
161     return false;
162   }
163
164   float w, h;
165   mPicture->size(&w, &h);
166   mDefaultWidth  = static_cast<uint32_t>(w);
167   mDefaultHeight = static_cast<uint32_t>(h);
168
169   return true;
170 #else
171   mParsedImage = nsvgParse(reinterpret_cast<char*>(data.Begin()), UNITS, dpi);
172   if(!mParsedImage || !mParsedImage->shapes)
173   {
174     DALI_LOG_ERROR("VectorImageRenderer::Load: nsvgParse failed\n");
175     return false;
176   }
177   return true;
178 #endif
179 }
180
181 bool VectorImageRenderer::Rasterize(Dali::Devel::PixelBuffer& buffer, float scale)
182 {
183 #ifdef THORVG_SUPPORT
184   if(!mSwCanvas || !mPicture)
185   {
186     DALI_LOG_ERROR("VectorImageRenderer::Rasterize: either Canvas[%p] or Picture[%p] is invalid [%p]\n", mSwCanvas.get(), mPicture, this);
187     return false;
188   }
189
190   mSwCanvas->clear(false);
191
192   auto pBuffer = buffer.GetBuffer();
193   if(!pBuffer)
194   {
195     DALI_LOG_ERROR("VectorImageRenderer::Rasterize: pixel buffer is null [%p]\n", this);
196     return false;
197   }
198
199   auto width  = buffer.GetWidth();
200   auto height = buffer.GetHeight();
201
202   mSwCanvas->target(reinterpret_cast<uint32_t*>(pBuffer), width, width, height, tvg::SwCanvas::ABGR8888);
203
204   DALI_LOG_RELEASE_INFO("VectorImageRenderer::Rasterize: Buffer[%p] size[%d x %d]! [%p]\n", pBuffer, width, height, this);
205
206   mPicture->size(width, height);
207
208   /* We can push everytime since we cleared the canvas just before. */
209   if(mSwCanvas->push(std::unique_ptr<tvg::Picture>(mPicture)) != tvg::Result::Success)
210   {
211     DALI_LOG_ERROR("VectorImageRenderer::Rasterize: Picture push fail [%p]\n", this);
212     return false;
213   }
214
215   auto ret = mSwCanvas->draw();
216   if(ret != tvg::Result::Success)
217   {
218     DALI_LOG_ERROR("VectorImageRenderer::Rasterize: Draw fail %d [%p]\n", static_cast<int>(ret), this);
219     return false;
220   }
221
222   mSwCanvas->sync();
223
224   return true;
225 #else
226   if(mParsedImage != nullptr)
227   {
228     int stride = buffer.GetWidth() * Pixel::GetBytesPerPixel(buffer.GetPixelFormat());
229     nsvgRasterize(mRasterizer, mParsedImage, 0.0f, 0.0f, scale, buffer.GetBuffer(), buffer.GetWidth(), buffer.GetHeight(), stride);
230     return true;
231   }
232   return false;
233 #endif
234 }
235
236 void VectorImageRenderer::GetDefaultSize(uint32_t& width, uint32_t& height) const
237 {
238 #ifdef THORVG_SUPPORT
239   width  = mDefaultWidth;
240   height = mDefaultHeight;
241 #else
242   if(mParsedImage)
243   {
244     width  = mParsedImage->width;
245     height = mParsedImage->height;
246   }
247 #endif
248 }
249
250 } // namespace Adaptor
251
252 } // namespace Internal
253
254 } // namespace Dali