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