b11ac2f010bab4ffed8faccf1d351b5ced938f32
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / svg / svg-rasterize-thread.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 "svg-rasterize-thread.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/adaptor-framework/file-loader.h>
23 #include <dali/devel-api/adaptor-framework/thread-settings.h>
24 #include <dali/integration-api/adaptor-framework/adaptor.h>
25 #include <dali/integration-api/debug.h>
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/internal/visuals/svg/svg-visual.h>
29
30 namespace Dali
31 {
32 namespace Toolkit
33 {
34 namespace Internal
35 {
36 RasterizingTask::RasterizingTask(SvgVisual* svgRenderer, VectorImageRenderer vectorRenderer, const VisualUrl& url, float dpi, unsigned int width, unsigned int height)
37 : mSvgVisual(svgRenderer),
38   mVectorRenderer(vectorRenderer),
39   mUrl(url),
40   mDpi(dpi),
41   mWidth(width),
42   mHeight(height),
43   mLoadSuccess(false)
44 {
45 }
46
47 RasterizingTask::~RasterizingTask()
48 {
49 }
50
51 void RasterizingTask::Load()
52 {
53   if(!mUrl.IsLocalResource())
54   {
55     Dali::Vector<uint8_t> remoteBuffer;
56     if(!Dali::FileLoader::DownloadFileSynchronously(mUrl.GetUrl(), remoteBuffer))
57     {
58       DALI_LOG_ERROR("RasterizingTask::Load: Failed to download file! [%s]\n", mUrl.GetUrl().c_str());
59       return;
60     }
61
62     remoteBuffer.PushBack('\0');
63
64     DALI_LOG_RELEASE_INFO("RasterizingTask::Load: Try load data! [%s]\n", mUrl.GetUrl().c_str());
65
66     if(!mVectorRenderer.Load(remoteBuffer, mDpi))
67     {
68       DALI_LOG_ERROR("RasterizingTask::Load:Failed to load data! [%s]\n", mUrl.GetUrl().c_str());
69       return;
70     }
71
72     mLoadSuccess = true;
73   }
74   else
75   {
76     mLoadSuccess = true;
77   }
78 }
79
80 void RasterizingTask::Rasterize()
81 {
82   if(mWidth <= 0u || mHeight <= 0u)
83   {
84     DALI_LOG_ERROR("RasterizingTask::Rasterize: Size is zero!\n");
85     return;
86   }
87
88   Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New(mWidth, mHeight, Dali::Pixel::RGBA8888);
89
90   uint32_t defaultWidth, defaultHeight;
91   mVectorRenderer.GetDefaultSize(defaultWidth, defaultHeight);
92
93   float scaleX = static_cast<float>(mWidth) / static_cast<float>(defaultWidth);
94   float scaleY = static_cast<float>(mHeight) / static_cast<float>(defaultHeight);
95   float scale  = scaleX < scaleY ? scaleX : scaleY;
96
97   if(!mVectorRenderer.Rasterize(pixelBuffer, scale))
98   {
99     DALI_LOG_ERROR("RasterizingTask::Rasterize: Rasterize is failed! [%s]\n", mUrl.GetUrl().c_str());
100     return;
101   }
102
103   mPixelData = Devel::PixelBuffer::Convert(pixelBuffer);
104 }
105
106 VectorImageRenderer RasterizingTask::GetVectorRenderer() const
107 {
108   return mVectorRenderer;
109 }
110
111 bool RasterizingTask::IsLoaded() const
112 {
113   return mLoadSuccess;
114 }
115
116 SvgVisual* RasterizingTask::GetSvgVisual() const
117 {
118   return mSvgVisual.Get();
119 }
120
121 PixelData RasterizingTask::GetPixelData() const
122 {
123   return mPixelData;
124 }
125
126 SvgRasterizeThread::SvgRasterizeThread()
127 : mTrigger(new EventThreadCallback(MakeCallback(this, &SvgRasterizeThread::ApplyRasterizedSVGToSampler))),
128   mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
129   mIsThreadWaiting(false),
130   mProcessorRegistered(false)
131 {
132 }
133
134 SvgRasterizeThread::~SvgRasterizeThread()
135 {
136   if(mProcessorRegistered)
137   {
138     Adaptor::Get().UnregisterProcessor(*this);
139   }
140 }
141
142 void SvgRasterizeThread::TerminateThread(SvgRasterizeThread*& thread)
143 {
144   if(thread)
145   {
146     // add an empty task would stop the thread from conditional wait.
147     thread->AddTask(RasterizingTaskPtr());
148     // stop the thread
149     thread->Join();
150     // delete the thread
151     delete thread;
152     thread = NULL;
153   }
154 }
155
156 void SvgRasterizeThread::AddTask(RasterizingTaskPtr task)
157 {
158   bool wasEmpty = false;
159
160   {
161     // Lock while adding task to the queue
162     ConditionalWait::ScopedLock lock(mConditionalWait);
163     wasEmpty = mRasterizeTasks.empty();
164     if(!wasEmpty && task != NULL)
165     {
166       // Remove the tasks with the same renderer.
167       // Older task which waiting to rasterize and apply the svg to the same renderer is expired.
168       for(std::vector<RasterizingTaskPtr>::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it)
169       {
170         if((*it) && (*it)->GetSvgVisual() == task->GetSvgVisual())
171         {
172           mRasterizeTasks.erase(it);
173           break;
174         }
175       }
176     }
177     mRasterizeTasks.push_back(task);
178
179     if(!mProcessorRegistered)
180     {
181       Adaptor::Get().RegisterProcessor(*this);
182       mProcessorRegistered = true;
183     }
184   }
185
186   if(wasEmpty)
187   {
188     // wake up the image loading thread
189     mConditionalWait.Notify();
190   }
191 }
192
193 RasterizingTaskPtr SvgRasterizeThread::NextCompletedTask()
194 {
195   // Lock while popping task out from the queue
196   Mutex::ScopedLock lock(mMutex);
197
198   if(mCompletedTasks.empty())
199   {
200     return RasterizingTaskPtr();
201   }
202
203   std::vector<RasterizingTaskPtr>::iterator next     = mCompletedTasks.begin();
204   RasterizingTaskPtr                        nextTask = *next;
205   mCompletedTasks.erase(next);
206
207   return nextTask;
208 }
209
210 void SvgRasterizeThread::RemoveTask(SvgVisual* visual)
211 {
212   // Lock while remove task from the queue
213   ConditionalWait::ScopedLock lock(mConditionalWait);
214   if(!mRasterizeTasks.empty())
215   {
216     for(std::vector<RasterizingTaskPtr>::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it)
217     {
218       if((*it) && (*it)->GetSvgVisual() == visual)
219       {
220         mRasterizeTasks.erase(it);
221         break;
222       }
223     }
224   }
225
226   UnregisterProcessor();
227 }
228
229 RasterizingTaskPtr SvgRasterizeThread::NextTaskToProcess()
230 {
231   // Lock while popping task out from the queue
232   ConditionalWait::ScopedLock lock(mConditionalWait);
233
234   // conditional wait
235   while(mRasterizeTasks.empty())
236   {
237     mIsThreadWaiting = true;
238     mConditionalWait.Wait(lock);
239   }
240   mIsThreadWaiting = false;
241
242   // pop out the next task from the queue
243   std::vector<RasterizingTaskPtr>::iterator next     = mRasterizeTasks.begin();
244   RasterizingTaskPtr                        nextTask = *next;
245   mRasterizeTasks.erase(next);
246
247   return nextTask;
248 }
249
250 void SvgRasterizeThread::AddCompletedTask(RasterizingTaskPtr task)
251 {
252   // Lock while adding task to the queue
253   Mutex::ScopedLock lock(mMutex);
254   mCompletedTasks.push_back(task);
255
256   // wake up the main thread
257   mTrigger->Trigger();
258 }
259
260 void SvgRasterizeThread::Run()
261 {
262   SetThreadName("SVGThread");
263   mLogFactory.InstallLogFunction();
264
265   while(RasterizingTaskPtr task = NextTaskToProcess())
266   {
267     task->Load();
268     task->Rasterize();
269     AddCompletedTask(task);
270   }
271 }
272
273 void SvgRasterizeThread::ApplyRasterizedSVGToSampler()
274 {
275   while(RasterizingTaskPtr task = NextCompletedTask())
276   {
277     task->GetSvgVisual()->ApplyRasterizedImage(task->GetVectorRenderer(), task->GetPixelData(), task->IsLoaded());
278   }
279
280   UnregisterProcessor();
281 }
282
283 void SvgRasterizeThread::Process(bool postProcessor)
284 {
285   ApplyRasterizedSVGToSampler();
286 }
287
288 void SvgRasterizeThread::UnregisterProcessor()
289 {
290   if(mProcessorRegistered)
291   {
292     if(mRasterizeTasks.empty() && mCompletedTasks.empty())
293     {
294       Adaptor::Get().UnregisterProcessor(*this);
295       mProcessorRegistered = false;
296     }
297   }
298 }
299
300 } // namespace Internal
301
302 } // namespace Toolkit
303
304 } // namespace Dali