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( EventThreadCallback* trigger )
125 : mTrigger( std::unique_ptr< EventThreadCallback >(trigger) ),
126 mLogFactory( Dali::Adaptor::Get().GetLogFactory() ),
127 mIsThreadWaiting( false )
131 SvgRasterizeThread::~SvgRasterizeThread()
135 void SvgRasterizeThread::TerminateThread( SvgRasterizeThread*& thread )
139 // add an empty task would stop the thread from conditional wait.
140 thread->AddTask( RasterizingTaskPtr() );
149 void SvgRasterizeThread::AddTask( RasterizingTaskPtr task )
151 bool wasEmpty = false;
154 // Lock while adding task to the queue
155 ConditionalWait::ScopedLock lock( mConditionalWait );
156 wasEmpty = mRasterizeTasks.empty();
157 if( !wasEmpty && task != NULL)
159 // Remove the tasks with the same renderer.
160 // Older task which waiting to rasterize and apply the svg to the same renderer is expired.
161 for( std::vector< RasterizingTaskPtr >::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it )
163 if( (*it) && (*it)->GetSvgVisual() == task->GetSvgVisual() )
165 mRasterizeTasks.erase( it );
170 mRasterizeTasks.push_back( task );
175 // wake up the image loading thread
176 mConditionalWait.Notify();
180 RasterizingTaskPtr SvgRasterizeThread::NextCompletedTask()
182 // Lock while popping task out from the queue
183 Mutex::ScopedLock lock( mMutex );
185 if( mCompletedTasks.empty() )
187 return RasterizingTaskPtr();
190 std::vector< RasterizingTaskPtr >::iterator next = mCompletedTasks.begin();
191 RasterizingTaskPtr nextTask = *next;
192 mCompletedTasks.erase( next );
197 void SvgRasterizeThread::RemoveTask( SvgVisual* visual )
199 // Lock while remove task from the queue
200 ConditionalWait::ScopedLock lock( mConditionalWait );
201 if( !mRasterizeTasks.empty() )
203 for( std::vector< RasterizingTaskPtr >::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it )
205 if( (*it) && (*it)->GetSvgVisual() == visual )
207 mRasterizeTasks.erase( it );
214 void SvgRasterizeThread::DeleteImage( VectorImageRenderer vectorRenderer )
216 // Lock while adding image to the delete queue
217 ConditionalWait::ScopedLock lock( mConditionalWait );
219 if( mIsThreadWaiting ) // no rasterization is ongoing, save to delete
223 else // wait to delete until current rasterization completed.
225 mDeleteSvg.PushBack( &vectorRenderer );
229 RasterizingTaskPtr SvgRasterizeThread::NextTaskToProcess()
231 // Lock while popping task out from the queue
232 ConditionalWait::ScopedLock lock( mConditionalWait );
234 // Delete the image here to make sure that it is not used in the nsvgRasterize()
235 if( !mDeleteSvg.Empty() )
241 while( mRasterizeTasks.empty() )
243 mIsThreadWaiting = true;
244 mConditionalWait.Wait( lock );
246 mIsThreadWaiting = false;
248 // pop out the next task from the queue
249 std::vector< RasterizingTaskPtr >::iterator next = mRasterizeTasks.begin();
250 RasterizingTaskPtr nextTask = *next;
251 mRasterizeTasks.erase( next );
256 void SvgRasterizeThread::AddCompletedTask( RasterizingTaskPtr task )
258 // Lock while adding task to the queue
259 Mutex::ScopedLock lock( mMutex );
260 mCompletedTasks.push_back( task );
262 // wake up the main thread
266 void SvgRasterizeThread::Run()
268 SetThreadName( "SVGThread" );
269 mLogFactory.InstallLogFunction();
271 while( RasterizingTaskPtr task = NextTaskToProcess() )
275 AddCompletedTask( task );
279 } // namespace Internal
281 } // namespace Toolkit