2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "svg-rasterize-thread.h"
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>
28 #include <dali-toolkit/internal/visuals/svg/svg-visual.h>
38 RasterizingTask::RasterizingTask(SvgVisual* svgRenderer, VectorImageRenderer vectorRenderer, const VisualUrl& url, float dpi, unsigned int width, unsigned int height)
39 : mSvgVisual(svgRenderer),
40 mVectorRenderer(vectorRenderer),
50 RasterizingTask::~RasterizingTask()
54 void RasterizingTask::Load()
56 if(!mUrl.IsLocalResource())
58 Dali::Vector<uint8_t> remoteBuffer;
59 if(!Dali::FileLoader::DownloadFileSynchronously(mUrl.GetUrl(), remoteBuffer))
61 DALI_LOG_ERROR("RasterizingTask::Load: Failed to download file! [%s]\n", mUrl.GetUrl().c_str());
65 remoteBuffer.PushBack('\0');
67 if(!mVectorRenderer.Load(remoteBuffer, mDpi))
69 DALI_LOG_ERROR("RasterizingTask::Load:Failed to load data! [%s]\n", mUrl.GetUrl().c_str());
81 void RasterizingTask::Rasterize()
83 if(mWidth <= 0u || mHeight <= 0u)
85 DALI_LOG_ERROR("RasterizingTask::Rasterize: Size is zero!\n");
89 Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New(mWidth, mHeight, Dali::Pixel::RGBA8888);
91 uint32_t defaultWidth, defaultHeight;
92 mVectorRenderer.GetDefaultSize(defaultWidth, defaultHeight);
94 float scaleX = static_cast<float>(mWidth) / static_cast<float>(defaultWidth);
95 float scaleY = static_cast<float>(mHeight) / static_cast<float>(defaultHeight);
96 float scale = scaleX < scaleY ? scaleX : scaleY;
98 if(!mVectorRenderer.Rasterize(pixelBuffer, scale))
100 DALI_LOG_ERROR("RasterizingTask::Rasterize: Rasterize is failed! [%s]\n", mUrl.GetUrl().c_str());
104 mPixelData = Devel::PixelBuffer::Convert(pixelBuffer);
107 VectorImageRenderer RasterizingTask::GetVectorRenderer() const
109 return mVectorRenderer;
112 bool RasterizingTask::IsLoaded() const
117 SvgVisual* RasterizingTask::GetSvgVisual() const
119 return mSvgVisual.Get();
122 PixelData RasterizingTask::GetPixelData() const
127 SvgRasterizeThread::SvgRasterizeThread()
128 : mTrigger( new EventThreadCallback( MakeCallback( this, &SvgRasterizeThread::ApplyRasterizedSVGToSampler ) ) ),
129 mLogFactory( Dali::Adaptor::Get().GetLogFactory() ),
130 mIsThreadWaiting( false ),
131 mProcessorRegistered( false )
135 SvgRasterizeThread::~SvgRasterizeThread()
137 if( mProcessorRegistered )
139 Adaptor::Get().UnregisterProcessor( *this );
143 void SvgRasterizeThread::TerminateThread( SvgRasterizeThread*& thread )
147 // add an empty task would stop the thread from conditional wait.
148 thread->AddTask( RasterizingTaskPtr() );
157 void SvgRasterizeThread::AddTask( RasterizingTaskPtr task )
159 bool wasEmpty = false;
162 // Lock while adding task to the queue
163 ConditionalWait::ScopedLock lock( mConditionalWait );
164 wasEmpty = mRasterizeTasks.empty();
165 if( !wasEmpty && task != NULL)
167 // Remove the tasks with the same renderer.
168 // Older task which waiting to rasterize and apply the svg to the same renderer is expired.
169 for( std::vector< RasterizingTaskPtr >::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it )
171 if( (*it) && (*it)->GetSvgVisual() == task->GetSvgVisual() )
173 mRasterizeTasks.erase( it );
178 mRasterizeTasks.push_back( task );
180 if( !mProcessorRegistered )
182 Adaptor::Get().RegisterProcessor( *this );
183 mProcessorRegistered = true;
189 // wake up the image loading thread
190 mConditionalWait.Notify();
194 RasterizingTaskPtr SvgRasterizeThread::NextCompletedTask()
196 // Lock while popping task out from the queue
197 Mutex::ScopedLock lock( mMutex );
199 if( mCompletedTasks.empty() )
201 return RasterizingTaskPtr();
204 std::vector< RasterizingTaskPtr >::iterator next = mCompletedTasks.begin();
205 RasterizingTaskPtr nextTask = *next;
206 mCompletedTasks.erase( next );
211 void SvgRasterizeThread::RemoveTask( SvgVisual* visual )
213 // Lock while remove task from the queue
214 ConditionalWait::ScopedLock lock( mConditionalWait );
215 if( !mRasterizeTasks.empty() )
217 for( std::vector< RasterizingTaskPtr >::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it )
219 if( (*it) && (*it)->GetSvgVisual() == visual )
221 mRasterizeTasks.erase( it );
227 UnregisterProcessor();
230 void SvgRasterizeThread::DeleteImage( VectorImageRenderer vectorRenderer )
232 // Lock while adding image to the delete queue
233 ConditionalWait::ScopedLock lock( mConditionalWait );
235 if( mIsThreadWaiting ) // no rasterization is ongoing, save to delete
239 else // wait to delete until current rasterization completed.
241 mDeleteSvg.PushBack( &vectorRenderer );
245 RasterizingTaskPtr SvgRasterizeThread::NextTaskToProcess()
247 // Lock while popping task out from the queue
248 ConditionalWait::ScopedLock lock( mConditionalWait );
250 // Delete the image here to make sure that it is not used in the nsvgRasterize()
251 if( !mDeleteSvg.Empty() )
257 while( mRasterizeTasks.empty() )
259 mIsThreadWaiting = true;
260 mConditionalWait.Wait( lock );
262 mIsThreadWaiting = false;
264 // pop out the next task from the queue
265 std::vector< RasterizingTaskPtr >::iterator next = mRasterizeTasks.begin();
266 RasterizingTaskPtr nextTask = *next;
267 mRasterizeTasks.erase( next );
272 void SvgRasterizeThread::AddCompletedTask( RasterizingTaskPtr task )
274 // Lock while adding task to the queue
275 Mutex::ScopedLock lock( mMutex );
276 mCompletedTasks.push_back( task );
278 // wake up the main thread
282 void SvgRasterizeThread::Run()
284 SetThreadName( "SVGThread" );
285 mLogFactory.InstallLogFunction();
287 while( RasterizingTaskPtr task = NextTaskToProcess() )
291 AddCompletedTask( task );
295 void SvgRasterizeThread::ApplyRasterizedSVGToSampler()
297 while( RasterizingTaskPtr task = NextCompletedTask() )
299 task->GetSvgVisual()->ApplyRasterizedImage(task->GetVectorRenderer(), task->GetPixelData(), task->IsLoaded());
302 UnregisterProcessor();
305 void SvgRasterizeThread::Process()
307 ApplyRasterizedSVGToSampler();
310 void SvgRasterizeThread::UnregisterProcessor()
312 if ( mProcessorRegistered )
314 if( mRasterizeTasks.empty() && mCompletedTasks.empty() )
316 Adaptor::Get().UnregisterProcessor( *this );
317 mProcessorRegistered = false;
323 } // namespace Internal
325 } // namespace Toolkit