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>
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 ),
51 RasterizingTask::~RasterizingTask()
55 void RasterizingTask::Load()
57 if(!mLoaded && !mUrl.IsLocalResource())
59 Dali::Vector<uint8_t> remoteBuffer;
60 if(!Dali::FileLoader::DownloadFileSynchronously(mUrl.GetUrl(), remoteBuffer))
62 DALI_LOG_ERROR("RasterizingTask::Load: Failed to download file! [%s]\n", mUrl.GetUrl().c_str());
66 remoteBuffer.PushBack('\0');
68 if(!mVectorRenderer.Load(remoteBuffer, mDpi))
70 DALI_LOG_ERROR("RasterizingTask::Load:Failed to load data! [%s]\n", mUrl.GetUrl().c_str());
78 void RasterizingTask::Rasterize()
80 if(mWidth <= 0u || mHeight <= 0u)
82 DALI_LOG_ERROR("RasterizingTask::Rasterize: Size is zero!\n");
86 Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New(mWidth, mHeight, Dali::Pixel::RGBA8888);
88 uint32_t defaultWidth, defaultHeight;
89 mVectorRenderer.GetDefaultSize(defaultWidth, defaultHeight);
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;
95 if(!mVectorRenderer.Rasterize(pixelBuffer, scale))
97 DALI_LOG_ERROR("RasterizingTask::Rasterize: Rasterize is failed! [%s]\n", mUrl.GetUrl().c_str());
101 mPixelData = Devel::PixelBuffer::Convert(pixelBuffer);
104 VectorImageRenderer RasterizingTask::GetVectorRenderer() const
106 return mVectorRenderer;
109 bool RasterizingTask::IsLoaded() const
114 SvgVisual* RasterizingTask::GetSvgVisual() const
116 return mSvgVisual.Get();
119 PixelData RasterizingTask::GetPixelData() const
124 SvgRasterizeThread::SvgRasterizeThread()
125 : mTrigger( new EventThreadCallback( MakeCallback( this, &SvgRasterizeThread::ApplyRasterizedSVGToSampler ) ) ),
126 mLogFactory( Dali::Adaptor::Get().GetLogFactory() ),
127 mIsThreadWaiting( false ),
128 mProcessorRegistered( false )
132 SvgRasterizeThread::~SvgRasterizeThread()
134 if( mProcessorRegistered )
136 Adaptor::Get().UnregisterProcessor( *this );
140 void SvgRasterizeThread::TerminateThread( SvgRasterizeThread*& thread )
144 // add an empty task would stop the thread from conditional wait.
145 thread->AddTask( RasterizingTaskPtr() );
154 void SvgRasterizeThread::AddTask( RasterizingTaskPtr task )
156 bool wasEmpty = false;
159 // Lock while adding task to the queue
160 ConditionalWait::ScopedLock lock( mConditionalWait );
161 wasEmpty = mRasterizeTasks.empty();
162 if( !wasEmpty && task != NULL)
164 // Remove the tasks with the same renderer.
165 // Older task which waiting to rasterize and apply the svg to the same renderer is expired.
166 for( std::vector< RasterizingTaskPtr >::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it )
168 if( (*it) && (*it)->GetSvgVisual() == task->GetSvgVisual() )
170 mRasterizeTasks.erase( it );
175 mRasterizeTasks.push_back( task );
177 if( !mProcessorRegistered )
179 Adaptor::Get().RegisterProcessor( *this );
180 mProcessorRegistered = true;
186 // wake up the image loading thread
187 mConditionalWait.Notify();
191 RasterizingTaskPtr SvgRasterizeThread::NextCompletedTask()
193 // Lock while popping task out from the queue
194 Mutex::ScopedLock lock( mMutex );
196 if( mCompletedTasks.empty() )
198 return RasterizingTaskPtr();
201 std::vector< RasterizingTaskPtr >::iterator next = mCompletedTasks.begin();
202 RasterizingTaskPtr nextTask = *next;
203 mCompletedTasks.erase( next );
208 void SvgRasterizeThread::RemoveTask( SvgVisual* visual )
210 // Lock while remove task from the queue
211 ConditionalWait::ScopedLock lock( mConditionalWait );
212 if( !mRasterizeTasks.empty() )
214 for( std::vector< RasterizingTaskPtr >::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it )
216 if( (*it) && (*it)->GetSvgVisual() == visual )
218 mRasterizeTasks.erase( it );
224 UnregisterProcessor();
227 void SvgRasterizeThread::DeleteImage( VectorImageRenderer vectorRenderer )
229 // Lock while adding image to the delete queue
230 ConditionalWait::ScopedLock lock( mConditionalWait );
232 if( mIsThreadWaiting ) // no rasterization is ongoing, save to delete
236 else // wait to delete until current rasterization completed.
238 mDeleteSvg.PushBack( &vectorRenderer );
242 RasterizingTaskPtr SvgRasterizeThread::NextTaskToProcess()
244 // Lock while popping task out from the queue
245 ConditionalWait::ScopedLock lock( mConditionalWait );
247 // Delete the image here to make sure that it is not used in the nsvgRasterize()
248 if( !mDeleteSvg.Empty() )
254 while( mRasterizeTasks.empty() )
256 mIsThreadWaiting = true;
257 mConditionalWait.Wait( lock );
259 mIsThreadWaiting = false;
261 // pop out the next task from the queue
262 std::vector< RasterizingTaskPtr >::iterator next = mRasterizeTasks.begin();
263 RasterizingTaskPtr nextTask = *next;
264 mRasterizeTasks.erase( next );
269 void SvgRasterizeThread::AddCompletedTask( RasterizingTaskPtr task )
271 // Lock while adding task to the queue
272 Mutex::ScopedLock lock( mMutex );
273 mCompletedTasks.push_back( task );
275 // wake up the main thread
279 void SvgRasterizeThread::Run()
281 SetThreadName( "SVGThread" );
282 mLogFactory.InstallLogFunction();
284 while( RasterizingTaskPtr task = NextTaskToProcess() )
288 AddCompletedTask( task );
292 void SvgRasterizeThread::ApplyRasterizedSVGToSampler()
294 while( RasterizingTaskPtr task = NextCompletedTask() )
296 task->GetSvgVisual()->ApplyRasterizedImage(task->GetVectorRenderer(), task->GetPixelData(), task->IsLoaded());
299 UnregisterProcessor();
302 void SvgRasterizeThread::Process()
304 ApplyRasterizedSVGToSampler();
307 void SvgRasterizeThread::UnregisterProcessor()
309 if ( mProcessorRegistered )
311 if( mRasterizeTasks.empty() && mCompletedTasks.empty() )
313 Adaptor::Get().UnregisterProcessor( *this );
314 mProcessorRegistered = false;
320 } // namespace Internal
322 } // namespace Toolkit