[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / svg / svg-task.cpp
1 /*
2  * Copyright (c) 2024 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-toolkit/internal/visuals/svg/svg-task.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/adaptor-framework/file-loader.h>
23 #include <dali/integration-api/adaptor-framework/adaptor.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/integration-api/trace.h>
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/internal/visuals/svg/svg-visual.h>
29
30 #ifdef TRACE_ENABLED
31 #include <chrono>
32 #include <iomanip>
33 #include <sstream>
34 #include <thread>
35 #endif
36
37 namespace Dali
38 {
39 namespace Toolkit
40 {
41 namespace Internal
42 {
43 namespace
44 {
45 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_IMAGE_PERFORMANCE_MARKER, false);
46
47 #ifdef TRACE_ENABLED
48 uint64_t GetNanoseconds()
49 {
50   // Get the time of a monotonic clock since its epoch.
51   auto epoch    = std::chrono::steady_clock::now().time_since_epoch();
52   auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(epoch);
53   return static_cast<uint64_t>(duration.count());
54 }
55 #endif
56 } // namespace
57
58 SvgTask::SvgTask(VectorImageRenderer vectorRenderer, CallbackBase* callback, AsyncTask::PriorityType priorityType)
59 : AsyncTask(callback, priorityType),
60   mVectorRenderer(vectorRenderer),
61   mHasSucceeded(false)
62 {
63 }
64
65 PixelData SvgTask::GetPixelData() const
66 {
67   return PixelData();
68 }
69
70 bool SvgTask::HasSucceeded() const
71 {
72   return mHasSucceeded;
73 }
74
75 VectorImageRenderer SvgTask::GetRenderer()
76 {
77   return mVectorRenderer;
78 }
79
80 SvgLoadingTask::SvgLoadingTask(VectorImageRenderer vectorRenderer, const VisualUrl& url, EncodedImageBuffer encodedImageBuffer, float dpi, CallbackBase* callback)
81 : SvgTask(vectorRenderer, callback, url.GetProtocolType() == VisualUrl::ProtocolType::REMOTE ? AsyncTask::PriorityType::LOW : AsyncTask::PriorityType::HIGH),
82   mImageUrl(url),
83   mEncodedImageBuffer(encodedImageBuffer),
84   mDpi(dpi)
85 {
86 }
87
88 SvgLoadingTask::~SvgLoadingTask()
89 {
90 }
91
92 void SvgLoadingTask::Process()
93 {
94   if(mVectorRenderer.IsLoaded())
95   {
96     // Already loaded
97     mHasSucceeded = true;
98     return;
99   }
100
101 #ifdef TRACE_ENABLED
102   uint64_t mStartTimeNanoSceonds = 0;
103   uint64_t mEndTimeNanoSceonds   = 0;
104   if(gTraceFilter && gTraceFilter->IsTraceEnabled())
105   {
106     mStartTimeNanoSceonds = GetNanoseconds();
107     std::ostringstream oss;
108     oss << "[u:" << mImageUrl.GetEllipsedUrl() << "]";
109     // DALI_TRACE_BEGIN(gTraceFilter, "DALI_SVG_LOADING_TASK"); ///< TODO : Open it if we can control trace log level
110     DALI_LOG_RELEASE_INFO("BEGIN: DALI_SVG_LOADING_TASK %s", oss.str().c_str());
111   }
112 #endif
113
114   bool loadFailed = false;
115
116   Dali::Vector<uint8_t> buffer;
117
118   if(mEncodedImageBuffer)
119   {
120     // Copy raw buffer.
121     // TODO : Can't we load svg without copy buffer in future?
122     buffer = mEncodedImageBuffer.GetRawBuffer();
123
124     // We don't need to hold image buffer anymore.
125     mEncodedImageBuffer.Reset();
126   }
127   else if(mImageUrl.IsLocalResource())
128   {
129     if(!Dali::FileLoader::ReadFile(mImageUrl.GetUrl(), buffer))
130     {
131       DALI_LOG_ERROR("Failed to read file! [%s]\n", mImageUrl.GetUrl().c_str());
132       loadFailed = true;
133     }
134   }
135   else
136   {
137     if(!Dali::FileLoader::DownloadFileSynchronously(mImageUrl.GetUrl(), buffer))
138     {
139       DALI_LOG_ERROR("Failed to download file! [%s]\n", mImageUrl.GetUrl().c_str());
140       loadFailed = true;
141     }
142   }
143
144   if(!loadFailed)
145   {
146     buffer.Reserve(buffer.Count() + 1u);
147     buffer.PushBack('\0');
148
149     if(!mVectorRenderer.Load(buffer, mDpi))
150     {
151       DALI_LOG_ERROR("Failed to load data! [%s]\n", mImageUrl.GetUrl().c_str());
152       loadFailed = true;
153     }
154   }
155
156   mHasSucceeded = !loadFailed;
157 #ifdef TRACE_ENABLED
158   if(gTraceFilter && gTraceFilter->IsTraceEnabled())
159   {
160     mEndTimeNanoSceonds = GetNanoseconds();
161     std::ostringstream oss;
162     oss << std::fixed << std::setprecision(3);
163     oss << "[";
164     oss << "d:" << static_cast<float>(mEndTimeNanoSceonds - mStartTimeNanoSceonds) / 1000000.0f << "ms ";
165     oss << "s:" << mHasSucceeded << " ";
166     oss << "u:" << mImageUrl.GetEllipsedUrl() << "]";
167     // DALI_TRACE_END(gTraceFilter, "DALI_SVG_LOADING_TASK"); ///< TODO : Open it if we can control trace log level
168     DALI_LOG_RELEASE_INFO("END: DALI_SVG_LOADING_TASK %s", oss.str().c_str());
169   }
170 #endif
171 }
172
173 bool SvgLoadingTask::IsReady()
174 {
175   return true;
176 }
177
178 SvgRasterizingTask::SvgRasterizingTask(VectorImageRenderer vectorRenderer, uint32_t width, uint32_t height, CallbackBase* callback)
179 : SvgTask(vectorRenderer, callback),
180   mWidth(width),
181   mHeight(height)
182 {
183 }
184
185 SvgRasterizingTask::~SvgRasterizingTask()
186 {
187 }
188
189 void SvgRasterizingTask::Process()
190 {
191   if(!mVectorRenderer.IsLoaded())
192   {
193     DALI_LOG_ERROR("File is not loaded!\n");
194     return;
195   }
196
197 #ifdef TRACE_ENABLED
198   uint64_t mStartTimeNanoSceonds = 0;
199   uint64_t mEndTimeNanoSceonds   = 0;
200 #endif
201   DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_SVG_RASTERIZE_TASK", [&](std::ostringstream& oss) {
202     mStartTimeNanoSceonds = GetNanoseconds();
203     oss << "[s:" << mWidth << "x" << mHeight << " ";
204     oss << "u:" << mImageUrl.GetEllipsedUrl() << "]";
205   });
206
207   Devel::PixelBuffer pixelBuffer = mVectorRenderer.Rasterize(mWidth, mHeight);
208   if(!pixelBuffer)
209   {
210     DALI_LOG_ERROR("Rasterize is failed!\n");
211     DALI_TRACE_END_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_SVG_RASTERIZE_TASK", [&](std::ostringstream& oss) {
212       oss << "[s:" << mWidth << "x" << mHeight << " ";
213       oss << "u:" << mImageUrl.GetEllipsedUrl() << "]";
214     });
215     return;
216   }
217
218   mPixelData    = Devel::PixelBuffer::Convert(pixelBuffer);
219   mHasSucceeded = true;
220
221   DALI_TRACE_END_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_SVG_RASTERIZE_TASK", [&](std::ostringstream& oss) {
222     mEndTimeNanoSceonds = GetNanoseconds();
223     oss << std::fixed << std::setprecision(3);
224     oss << "[";
225     oss << "d:" << static_cast<float>(mEndTimeNanoSceonds - mStartTimeNanoSceonds) / 1000000.0f << "ms ";
226     oss << "s:" << mWidth << "x" << mHeight << " ";
227     oss << "u:" << mImageUrl.GetEllipsedUrl() << "]";
228   });
229 }
230
231 bool SvgRasterizingTask::IsReady()
232 {
233   return mVectorRenderer.IsLoaded();
234 }
235
236 PixelData SvgRasterizingTask::GetPixelData() const
237 {
238   return mPixelData;
239 }
240
241 } // namespace Internal
242
243 } // namespace Toolkit
244
245 } // namespace Dali