Merge "Remove ResourceReady before rasterization in SvgVisual" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / svg / svg-rasterize-thread.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 "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     if(!mVectorRenderer.Load(remoteBuffer, mDpi))
65     {
66       DALI_LOG_ERROR("RasterizingTask::Load:Failed to load data! [%s]\n", mUrl.GetUrl().c_str());
67       return;
68     }
69
70     mLoadSuccess = true;
71   }
72   else
73   {
74     mLoadSuccess = true;
75   }
76 }
77
78 void RasterizingTask::Rasterize()
79 {
80   Devel::PixelBuffer pixelBuffer = mVectorRenderer.Rasterize(mWidth, mHeight);
81   if(!pixelBuffer)
82   {
83     DALI_LOG_ERROR("Rasterize is failed! [%s]\n", mUrl.GetUrl().c_str());
84     return;
85   }
86
87   mPixelData = Devel::PixelBuffer::Convert(pixelBuffer);
88 }
89
90 VectorImageRenderer RasterizingTask::GetVectorRenderer() const
91 {
92   return mVectorRenderer;
93 }
94
95 bool RasterizingTask::IsLoaded() const
96 {
97   return mLoadSuccess;
98 }
99
100 SvgVisual* RasterizingTask::GetSvgVisual() const
101 {
102   return mSvgVisual.Get();
103 }
104
105 PixelData RasterizingTask::GetPixelData() const
106 {
107   return mPixelData;
108 }
109
110 SvgRasterizeThread::SvgRasterizeThread()
111 : mTrigger(new EventThreadCallback(MakeCallback(this, &SvgRasterizeThread::ApplyRasterizedSVGToSampler))),
112   mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
113   mIsThreadWaiting(false),
114   mProcessorRegistered(false)
115 {
116 }
117
118 SvgRasterizeThread::~SvgRasterizeThread()
119 {
120   if(mProcessorRegistered)
121   {
122     Adaptor::Get().UnregisterProcessor(*this);
123   }
124 }
125
126 void SvgRasterizeThread::TerminateThread(SvgRasterizeThread*& thread)
127 {
128   if(thread)
129   {
130     // add an empty task would stop the thread from conditional wait.
131     thread->AddTask(RasterizingTaskPtr());
132     // stop the thread
133     thread->Join();
134     // delete the thread
135     delete thread;
136     thread = NULL;
137   }
138 }
139
140 void SvgRasterizeThread::AddTask(RasterizingTaskPtr task)
141 {
142   bool wasEmpty = false;
143
144   {
145     // Lock while adding task to the queue
146     ConditionalWait::ScopedLock lock(mConditionalWait);
147     wasEmpty = mRasterizeTasks.empty();
148     if(!wasEmpty && task)
149     {
150       // Remove the tasks with the same renderer.
151       // Older task which waiting to rasterize and apply the svg to the same renderer is expired.
152       for(std::vector<RasterizingTaskPtr>::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it)
153       {
154         if((*it) && (*it)->GetSvgVisual() == task->GetSvgVisual())
155         {
156           mRasterizeTasks.erase(it);
157           break;
158         }
159       }
160     }
161     mRasterizeTasks.push_back(task);
162
163     if(!mProcessorRegistered)
164     {
165       Adaptor::Get().RegisterProcessor(*this);
166       mProcessorRegistered = true;
167     }
168   }
169
170   if(wasEmpty)
171   {
172     // wake up the image loading thread
173     mConditionalWait.Notify();
174   }
175 }
176
177 RasterizingTaskPtr SvgRasterizeThread::NextCompletedTask()
178 {
179   // Lock while popping task out from the queue
180   Mutex::ScopedLock lock(mMutex);
181
182   if(mCompletedTasks.empty())
183   {
184     return RasterizingTaskPtr();
185   }
186
187   std::vector<RasterizingTaskPtr>::iterator next     = mCompletedTasks.begin();
188   RasterizingTaskPtr                        nextTask = *next;
189   mCompletedTasks.erase(next);
190
191   return nextTask;
192 }
193
194 void SvgRasterizeThread::RemoveTask(SvgVisual* visual)
195 {
196   // Lock while remove task from the queue
197   ConditionalWait::ScopedLock lock(mConditionalWait);
198   if(!mRasterizeTasks.empty())
199   {
200     for(std::vector<RasterizingTaskPtr>::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it)
201     {
202       if((*it) && (*it)->GetSvgVisual() == visual)
203       {
204         mRasterizeTasks.erase(it);
205         break;
206       }
207     }
208   }
209
210   UnregisterProcessor();
211 }
212
213 RasterizingTaskPtr SvgRasterizeThread::NextTaskToProcess()
214 {
215   // Lock while popping task out from the queue
216   ConditionalWait::ScopedLock lock(mConditionalWait);
217
218   // conditional wait
219   while(mRasterizeTasks.empty())
220   {
221     mIsThreadWaiting = true;
222     mConditionalWait.Wait(lock);
223   }
224   mIsThreadWaiting = false;
225
226   // pop out the next task from the queue
227   std::vector<RasterizingTaskPtr>::iterator next     = mRasterizeTasks.begin();
228   RasterizingTaskPtr                        nextTask = *next;
229   mRasterizeTasks.erase(next);
230
231   return nextTask;
232 }
233
234 void SvgRasterizeThread::AddCompletedTask(RasterizingTaskPtr task)
235 {
236   // Lock while adding task to the queue
237   Mutex::ScopedLock lock(mMutex);
238   mCompletedTasks.push_back(task);
239
240   // wake up the main thread
241   mTrigger->Trigger();
242 }
243
244 void SvgRasterizeThread::Run()
245 {
246   SetThreadName("SVGThread");
247   mLogFactory.InstallLogFunction();
248
249   while(RasterizingTaskPtr task = NextTaskToProcess())
250   {
251     task->Load();
252     task->Rasterize();
253     AddCompletedTask(task);
254   }
255 }
256
257 void SvgRasterizeThread::ApplyRasterizedSVGToSampler()
258 {
259   while(RasterizingTaskPtr task = NextCompletedTask())
260   {
261     task->GetSvgVisual()->ApplyRasterizedImage(task->GetVectorRenderer(), task->GetPixelData(), task->IsLoaded());
262   }
263
264   UnregisterProcessor();
265 }
266
267 void SvgRasterizeThread::Process(bool postProcessor)
268 {
269   ApplyRasterizedSVGToSampler();
270 }
271
272 void SvgRasterizeThread::UnregisterProcessor()
273 {
274   if(mProcessorRegistered)
275   {
276     if(mRasterizeTasks.empty() && mCompletedTasks.empty())
277     {
278       Adaptor::Get().UnregisterProcessor(*this);
279       mProcessorRegistered = false;
280     }
281   }
282 }
283
284 } // namespace Internal
285
286 } // namespace Toolkit
287
288 } // namespace Dali