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