SvgVisual: Using VectorImageRenderer
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / svg / svg-rasterize-thread.cpp
1 /*
2  * Copyright (c) 2016 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/debug.h>
25
26 // INTERNAL INCLUDES
27 #ifdef NO_THORVG
28 #include <dali-toolkit/third-party/nanosvg/nanosvgrast.h>
29 #endif /* NO_THORVG */
30 #include <dali-toolkit/internal/visuals/svg/svg-visual.h>
31
32 namespace Dali
33 {
34
35 namespace Toolkit
36 {
37
38 namespace Internal
39 {
40
41 namespace
42 {
43 const char * const UNITS("px");
44 }
45
46 #ifdef NO_THORVG
47 RasterizingTask::RasterizingTask( SvgVisual* svgRenderer, NSVGimage* parsedSvg, const VisualUrl& url, float dpi, unsigned int width, unsigned int height)
48 : mSvgVisual( svgRenderer ),
49   mParsedSvg( parsedSvg ),
50   mUrl( url ),
51   mDpi( dpi ),
52   mWidth( width ),
53   mHeight( height )
54 {
55   mRasterizer = nsvgCreateRasterizer();
56 }
57 #else /* NO_THORVG */
58 RasterizingTask::RasterizingTask( SvgVisual* svgRenderer, VectorImageRenderer vectorRenderer, const VisualUrl& url, float dpi, unsigned int width, unsigned int height, bool loaded)
59 : mSvgVisual( svgRenderer ),
60   mVectorRenderer( vectorRenderer ),
61   mUrl( url ),
62   mDpi( dpi ),
63   mWidth( width ),
64   mHeight( height ),
65   mLoaded( loaded )
66 {
67
68 }
69 #endif /* NO_THORVG */
70
71 RasterizingTask::~RasterizingTask()
72 {
73 #ifdef NO_THORVG
74   nsvgDeleteRasterizer( mRasterizer );
75 #endif /* NO_THORVG */
76 }
77
78 void RasterizingTask::Load()
79 {
80 #ifdef NO_THORVG
81   if( mParsedSvg != NULL)
82   {
83     return;
84   }
85
86   if( !mUrl.IsLocalResource() )
87   {
88     Dali::Vector<uint8_t> remoteBuffer;
89
90     if( !Dali::FileLoader::DownloadFileSynchronously( mUrl.GetUrl(), remoteBuffer ))
91     {
92       DALI_LOG_ERROR("Failed to download file!\n");
93       return;
94     }
95
96     remoteBuffer.PushBack( '\0' );
97     mParsedSvg = nsvgParse( reinterpret_cast<char*>(remoteBuffer.begin()), UNITS, mDpi );
98   }
99 #else /* NO_THORVG */
100   if( !mLoaded &&  !mUrl.IsLocalResource() )
101   {
102     Dali::Vector<uint8_t> remoteBuffer;
103
104     if( !Dali::FileLoader::DownloadFileSynchronously( mUrl.GetUrl(), remoteBuffer ))
105     {
106       DALI_LOG_ERROR("Failed to download file!\n");
107       return;
108     }
109
110     remoteBuffer.PushBack( '\0' );
111     char *data = reinterpret_cast<char*>(remoteBuffer.begin());
112     if ( !mVectorRenderer.Load( data, remoteBuffer.Size()))
113     {
114       DALI_LOG_ERROR( "Failed to load data!\n" );
115       return;
116     }
117
118     mLoaded = true;
119   }
120 #endif /* NO_THORVG */
121 }
122
123 void RasterizingTask::Rasterize( )
124 {
125 #ifdef NO_THORVG
126   if( mParsedSvg != NULL && mWidth > 0u && mHeight > 0u )
127   {
128     float scaleX = static_cast<float>( mWidth ) /  mParsedSvg->width;
129     float scaleY = static_cast<float>( mHeight ) /  mParsedSvg->height;
130     float scale = scaleX < scaleY ? scaleX : scaleY;
131     unsigned int bufferStride = mWidth*Pixel::GetBytesPerPixel( Pixel::RGBA8888 );
132     unsigned int bufferSize = bufferStride * mHeight;
133
134     unsigned char* buffer = new unsigned char [bufferSize];
135     nsvgRasterize(mRasterizer, mParsedSvg, 0.f,0.f,scale,
136         buffer, mWidth, mHeight,
137         bufferStride );
138
139     mPixelData = Dali::PixelData::New( buffer, bufferSize, mWidth, mHeight, Pixel::RGBA8888, Dali::PixelData::DELETE_ARRAY );
140   }
141 #else /* NO_THORVG */
142   if ( mWidth <= 0u || mHeight <= 0u )
143   {
144     DALI_LOG_ERROR( "Size is zero!\n" );
145     return;
146   }
147
148   Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New( mWidth, mHeight, Dali::Pixel::RGBA8888 );
149   mVectorRenderer.SetBuffer( pixelBuffer );
150   {
151     uint32_t defaultWidth, defaultHeight;
152     mVectorRenderer.GetDefaultSize( defaultWidth, defaultHeight );
153
154     float scaleX = static_cast<float>( mWidth ) / static_cast<float>( defaultWidth );
155     float scaleY = static_cast<float>( mHeight ) / static_cast<float>( defaultHeight );
156     float scale = scaleX < scaleY ? scaleX : scaleY;
157
158     if ( !mVectorRenderer.Render( scale ) )
159     {
160       DALI_LOG_ERROR( "SVG Render Fail!\n" );
161       return;
162     }
163
164     mPixelData = Devel::PixelBuffer::Convert( pixelBuffer );
165     if ( !mPixelData )
166     {
167       DALI_LOG_ERROR( "Pixel Data is null\n" );
168     }
169   }
170 #endif /* NO_THORVG */
171 }
172
173 #ifdef NO_THORVG
174 NSVGimage* RasterizingTask::GetParsedImage() const
175 {
176   return mParsedSvg;
177 }
178 #else /* NO_THORVG */
179 VectorImageRenderer RasterizingTask::GetVectorRenderer() const
180 {
181   return mVectorRenderer;
182 }
183
184 bool RasterizingTask::IsLoaded() const
185 {
186   return mLoaded;
187 }
188 #endif /* NO_THORVG */
189
190 SvgVisual* RasterizingTask::GetSvgVisual() const
191 {
192   return mSvgVisual.Get();
193 }
194
195 PixelData RasterizingTask::GetPixelData() const
196 {
197   return mPixelData;
198 }
199
200 SvgRasterizeThread::SvgRasterizeThread( EventThreadCallback* trigger )
201 : mTrigger( trigger ),
202   mIsThreadWaiting( false )
203 {
204 }
205
206 SvgRasterizeThread::~SvgRasterizeThread()
207 {
208   delete mTrigger;
209 }
210
211 void SvgRasterizeThread::TerminateThread( SvgRasterizeThread*& thread )
212 {
213   if( thread )
214   {
215     // add an empty task would stop the thread from conditional wait.
216     thread->AddTask( RasterizingTaskPtr() );
217     // stop the thread
218     thread->Join();
219     // delete the thread
220     delete thread;
221     thread = NULL;
222   }
223 }
224
225 void SvgRasterizeThread::AddTask( RasterizingTaskPtr task )
226 {
227   bool wasEmpty = false;
228
229   {
230     // Lock while adding task to the queue
231     ConditionalWait::ScopedLock lock( mConditionalWait );
232     wasEmpty = mRasterizeTasks.empty();
233     if( !wasEmpty && task != NULL)
234     {
235       // Remove the tasks with the same renderer.
236       // Older task which waiting to rasterize and apply the svg to the same renderer is expired.
237       for( std::vector< RasterizingTaskPtr >::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it )
238       {
239         if( (*it) && (*it)->GetSvgVisual() == task->GetSvgVisual() )
240         {
241           mRasterizeTasks.erase( it );
242           break;
243         }
244       }
245     }
246     mRasterizeTasks.push_back( task );
247   }
248
249   if( wasEmpty)
250   {
251     // wake up the image loading thread
252     mConditionalWait.Notify();
253   }
254 }
255
256 RasterizingTaskPtr SvgRasterizeThread::NextCompletedTask()
257 {
258   // Lock while popping task out from the queue
259   Mutex::ScopedLock lock( mMutex );
260
261   if( mCompletedTasks.empty() )
262   {
263     return RasterizingTaskPtr();
264   }
265
266   std::vector< RasterizingTaskPtr >::iterator next = mCompletedTasks.begin();
267   RasterizingTaskPtr nextTask = *next;
268   mCompletedTasks.erase( next );
269
270   return nextTask;
271 }
272
273 void SvgRasterizeThread::RemoveTask( SvgVisual* visual )
274 {
275   // Lock while remove task from the queue
276   ConditionalWait::ScopedLock lock( mConditionalWait );
277   if( !mRasterizeTasks.empty() )
278   {
279     for( std::vector< RasterizingTaskPtr >::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it )
280     {
281       if( (*it) &&  (*it)->GetSvgVisual() == visual )
282       {
283         mRasterizeTasks.erase( it );
284         break;
285       }
286     }
287   }
288 }
289
290 #ifdef NO_THORVG
291 void SvgRasterizeThread::DeleteImage( NSVGimage* parsedSvg )
292 {
293   // Lock while adding image to the delete queue
294   ConditionalWait::ScopedLock lock( mConditionalWait );
295
296   if( mIsThreadWaiting ) // no rasterization is ongoing, save to delete
297   {
298     nsvgDelete( parsedSvg );
299   }
300   else // wait to delete until current rasterization completed.
301   {
302     mDeleteSvg.PushBack( parsedSvg );
303   }
304 }
305 #else /* NO_THORVG */
306 void SvgRasterizeThread::DeleteImage( VectorImageRenderer vectorRenderer )
307 {
308   // Lock while adding image to the delete queue
309   ConditionalWait::ScopedLock lock( mConditionalWait );
310
311   if( mIsThreadWaiting ) // no rasterization is ongoing, save to delete
312   {
313     // TODO: what?
314   }
315   else // wait to delete until current rasterization completed.
316   {
317     mDeleteSvg.PushBack( &vectorRenderer );
318   }
319 }
320 #endif /* NO_THORVG */
321
322 RasterizingTaskPtr SvgRasterizeThread::NextTaskToProcess()
323 {
324   // Lock while popping task out from the queue
325   ConditionalWait::ScopedLock lock( mConditionalWait );
326
327   // Delete the image here to make sure that it is not used in the nsvgRasterize()
328   if( !mDeleteSvg.Empty() )
329   {
330 #ifdef NO_THORVG
331     for( Vector< NSVGimage* >::Iterator it = mDeleteSvg.Begin(), endIt = mDeleteSvg.End();
332         it != endIt;
333         ++it )
334     {
335       nsvgDelete( *it );
336     }
337 #endif /* NO_THORVG */
338     mDeleteSvg.Clear();
339   }
340
341   // conditional wait
342   while( mRasterizeTasks.empty() )
343   {
344     mIsThreadWaiting = true;
345     mConditionalWait.Wait( lock );
346   }
347   mIsThreadWaiting = false;
348
349   // pop out the next task from the queue
350   std::vector< RasterizingTaskPtr >::iterator next = mRasterizeTasks.begin();
351   RasterizingTaskPtr nextTask = *next;
352   mRasterizeTasks.erase( next );
353
354   return nextTask;
355 }
356
357 void SvgRasterizeThread::AddCompletedTask( RasterizingTaskPtr task )
358 {
359   // Lock while adding task to the queue
360   Mutex::ScopedLock lock( mMutex );
361   mCompletedTasks.push_back( task );
362
363   // wake up the main thread
364   mTrigger->Trigger();
365 }
366
367 void SvgRasterizeThread::Run()
368 {
369   SetThreadName( "SVGThread" );
370   while( RasterizingTaskPtr task = NextTaskToProcess() )
371   {
372     task->Load( );
373     task->Rasterize( );
374     AddCompletedTask( task );
375   }
376 }
377
378 } // namespace Internal
379
380 } // namespace Toolkit
381
382 } // namespace Dali