9e01462d4f2d1e479bc103b8e9fe0a4b589fbfda
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / renderers / 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 // INTERNAL INCLUDES
22 #include "nanosvg/nanosvgrast.h"
23 #include "svg-renderer.h"
24
25 namespace
26 {
27 const std::string TEXTURE_UNIFORM_NAME = "sTexture";
28 }
29
30 namespace Dali
31 {
32
33 namespace Toolkit
34 {
35
36 namespace Internal
37 {
38
39 RasterizingTask::RasterizingTask( SvgRenderer* svgRenderer, NSVGimage* parsedSvg, unsigned int width, unsigned int height )
40 : mSvgRenderer( svgRenderer ),
41   mParsedSvg( parsedSvg ),
42   mWidth( width ),
43   mHeight( height )
44 {
45 }
46
47 void RasterizingTask::Rasterize( NSVGrasterizer* rasterizer )
48 {
49   if( mWidth > 0u && mHeight > 0u )
50   {
51     float scaleX =  static_cast<float>( mWidth ) /  mParsedSvg->width;
52     float scaleY =  static_cast<float>( mHeight ) /  mParsedSvg->height;
53     float scale = scaleX < scaleY ? scaleX : scaleY;
54     unsigned int bufferStride = mWidth*Pixel::GetBytesPerPixel( Pixel::RGBA8888 );
55
56     unsigned char* buffer = new unsigned char [bufferStride*mHeight];
57     nsvgRasterize(rasterizer, mParsedSvg, 0.f,0.f,scale,
58         buffer, mWidth, mHeight,
59         bufferStride );
60
61     mPixelData = Dali::PixelData::New( buffer, mWidth, mHeight, Pixel::RGBA8888, Dali::PixelData::DELETE_ARRAY );
62   }
63 }
64
65 SvgRenderer* RasterizingTask::GetSvgRenderer() const
66 {
67   return mSvgRenderer.Get();
68 }
69
70 PixelDataPtr RasterizingTask::GetPixelData() const
71 {
72   return mPixelData;
73 }
74
75 SvgRasterizeThread::SvgRasterizeThread( EventThreadCallback* trigger )
76 : mTrigger( trigger ),
77   mIsThreadWaiting( false )
78 {
79   mRasterizer = nsvgCreateRasterizer();
80 }
81
82 SvgRasterizeThread::~SvgRasterizeThread()
83 {
84
85   nsvgDeleteRasterizer( mRasterizer );
86   delete mTrigger;
87 }
88
89 void SvgRasterizeThread::TerminateThread( SvgRasterizeThread*& thread )
90 {
91   if( thread )
92   {
93     // add an empty task would stop the thread from conditional wait.
94     thread->AddTask( RasterizingTaskPtr() );
95     // stop the thread
96     thread->Join();
97     // delete the thread
98     delete thread;
99     thread = NULL;
100   }
101 }
102
103 void SvgRasterizeThread::AddTask( RasterizingTaskPtr task )
104 {
105   bool wasEmpty = false;
106
107   {
108     // Lock while adding task to the queue
109     ConditionalWait::ScopedLock lock( mConditionalWait );
110     wasEmpty = mRasterizeTasks.empty();
111     if( !wasEmpty && task != NULL)
112     {
113       // Remove the tasks with the same material.
114       // Older task which waiting to rasterize and apply the svg to the same material is expired.
115       for( std::vector< RasterizingTaskPtr >::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it )
116       {
117         if( (*it) && (*it)->GetSvgRenderer() == task->GetSvgRenderer() )
118         {
119           mRasterizeTasks.erase( it );
120           break;
121         }
122       }
123     }
124     mRasterizeTasks.push_back( task );
125   }
126
127   if( wasEmpty)
128   {
129     // wake up the image loading thread
130     mConditionalWait.Notify();
131   }
132 }
133
134 RasterizingTaskPtr SvgRasterizeThread::NextCompletedTask()
135 {
136   // Lock while popping task out from the queue
137   Mutex::ScopedLock lock( mMutex );
138
139   if( mCompletedTasks.empty() )
140   {
141     return RasterizingTaskPtr();
142   }
143
144   std::vector< RasterizingTaskPtr >::iterator next = mCompletedTasks.begin();
145   RasterizingTaskPtr nextTask = *next;
146   mCompletedTasks.erase( next );
147
148   return nextTask;
149 }
150
151 void SvgRasterizeThread::RemoveTask( SvgRenderer* renderer )
152 {
153   // Lock while remove task from the queue
154   ConditionalWait::ScopedLock lock( mConditionalWait );
155   if( !mRasterizeTasks.empty() )
156   {
157     for( std::vector< RasterizingTaskPtr >::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it )
158     {
159       if( (*it) &&  (*it)->GetSvgRenderer() == renderer )
160       {
161         mRasterizeTasks.erase( it );
162         break;
163       }
164     }
165   }
166 }
167
168 void SvgRasterizeThread::DeleteImage( NSVGimage* parsedSvg )
169 {
170   // Lock while adding image to the delete queue
171   ConditionalWait::ScopedLock lock( mConditionalWait );
172
173   if( mIsThreadWaiting ) // no rasterization is ongoing, save to delete
174   {
175     nsvgDelete( parsedSvg );
176   }
177   else // wait to delete until current rasterization completed.
178   {
179     mDeleteSvg.PushBack( parsedSvg );
180   }
181 }
182
183 RasterizingTaskPtr SvgRasterizeThread::NextTaskToProcess()
184 {
185   // Lock while popping task out from the queue
186   ConditionalWait::ScopedLock lock( mConditionalWait );
187
188   // Delete the image here to make sure that it is not used in the nsvgRasterize()
189   if( !mDeleteSvg.Empty() )
190   {
191     for( Vector< NSVGimage* >::Iterator it = mDeleteSvg.Begin(), endIt = mDeleteSvg.End();
192         it != endIt;
193         ++it )
194     {
195       nsvgDelete( *it );
196     }
197     mDeleteSvg.Clear();
198   }
199
200   // conditional wait
201   while( mRasterizeTasks.empty() )
202   {
203     mIsThreadWaiting = true;
204     mConditionalWait.Wait( lock );
205   }
206   mIsThreadWaiting = false;
207
208   // pop out the next task from the queue
209   std::vector< RasterizingTaskPtr >::iterator next = mRasterizeTasks.begin();
210   RasterizingTaskPtr nextTask = *next;
211   mRasterizeTasks.erase( next );
212
213   return nextTask;
214 }
215
216 void SvgRasterizeThread::AddCompletedTask( RasterizingTaskPtr task )
217 {
218   // Lock while adding task to the queue
219   Mutex::ScopedLock lock( mMutex );
220   mCompletedTasks.push_back( task );
221
222   // wake up the main thread
223   mTrigger->Trigger();
224 }
225
226 void SvgRasterizeThread::Run()
227 {
228   while( RasterizingTaskPtr task = NextTaskToProcess() )
229   {
230     task->Rasterize( mRasterizer );
231     AddCompletedTask( task );
232   }
233 }
234
235 } // namespace Internal
236
237 } // namespace Toolkit
238
239 } // namespace Dali