2 * Copyright (c) 2021 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/file-loader.h>
23 #include <dali/devel-api/adaptor-framework/thread-settings.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>
36 RasterizingTask::RasterizingTask(SvgVisual* svgRenderer, VectorImageRenderer vectorRenderer, const VisualUrl& url, float dpi, unsigned int width, unsigned int height)
37 : mSvgVisual(svgRenderer),
38 mVectorRenderer(vectorRenderer),
47 RasterizingTask::~RasterizingTask()
51 void RasterizingTask::Load()
53 if(!mUrl.IsLocalResource())
55 Dali::Vector<uint8_t> remoteBuffer;
56 if(!Dali::FileLoader::DownloadFileSynchronously(mUrl.GetUrl(), remoteBuffer))
58 DALI_LOG_ERROR("RasterizingTask::Load: Failed to download file! [%s]\n", mUrl.GetUrl().c_str());
62 remoteBuffer.PushBack('\0');
64 DALI_LOG_RELEASE_INFO("RasterizingTask::Load: Try load data! [%s]\n", mUrl.GetUrl().c_str());
66 if(!mVectorRenderer.Load(remoteBuffer, mDpi))
68 DALI_LOG_ERROR("RasterizingTask::Load:Failed to load data! [%s]\n", mUrl.GetUrl().c_str());
80 void RasterizingTask::Rasterize()
82 if(mWidth <= 0u || mHeight <= 0u)
84 DALI_LOG_ERROR("RasterizingTask::Rasterize: Size is zero!\n");
88 Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New(mWidth, mHeight, Dali::Pixel::RGBA8888);
90 uint32_t defaultWidth, defaultHeight;
91 mVectorRenderer.GetDefaultSize(defaultWidth, defaultHeight);
93 float scaleX = static_cast<float>(mWidth) / static_cast<float>(defaultWidth);
94 float scaleY = static_cast<float>(mHeight) / static_cast<float>(defaultHeight);
95 float scale = scaleX < scaleY ? scaleX : scaleY;
97 if(!mVectorRenderer.Rasterize(pixelBuffer, scale))
99 DALI_LOG_ERROR("RasterizingTask::Rasterize: Rasterize is failed! [%s]\n", mUrl.GetUrl().c_str());
103 mPixelData = Devel::PixelBuffer::Convert(pixelBuffer);
106 VectorImageRenderer RasterizingTask::GetVectorRenderer() const
108 return mVectorRenderer;
111 bool RasterizingTask::IsLoaded() const
116 SvgVisual* RasterizingTask::GetSvgVisual() const
118 return mSvgVisual.Get();
121 PixelData RasterizingTask::GetPixelData() const
126 SvgRasterizeThread::SvgRasterizeThread()
127 : mTrigger(new EventThreadCallback(MakeCallback(this, &SvgRasterizeThread::ApplyRasterizedSVGToSampler))),
128 mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
129 mIsThreadWaiting(false),
130 mProcessorRegistered(false)
134 SvgRasterizeThread::~SvgRasterizeThread()
136 if(mProcessorRegistered)
138 Adaptor::Get().UnregisterProcessor(*this);
142 void SvgRasterizeThread::TerminateThread(SvgRasterizeThread*& thread)
146 // add an empty task would stop the thread from conditional wait.
147 thread->AddTask(RasterizingTaskPtr());
156 void SvgRasterizeThread::AddTask(RasterizingTaskPtr task)
158 bool wasEmpty = false;
161 // Lock while adding task to the queue
162 ConditionalWait::ScopedLock lock(mConditionalWait);
163 wasEmpty = mRasterizeTasks.empty();
164 if(!wasEmpty && task != NULL)
166 // Remove the tasks with the same renderer.
167 // Older task which waiting to rasterize and apply the svg to the same renderer is expired.
168 for(std::vector<RasterizingTaskPtr>::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it)
170 if((*it) && (*it)->GetSvgVisual() == task->GetSvgVisual())
172 mRasterizeTasks.erase(it);
177 mRasterizeTasks.push_back(task);
179 if(!mProcessorRegistered)
181 Adaptor::Get().RegisterProcessor(*this);
182 mProcessorRegistered = true;
188 // wake up the image loading thread
189 mConditionalWait.Notify();
193 RasterizingTaskPtr SvgRasterizeThread::NextCompletedTask()
195 // Lock while popping task out from the queue
196 Mutex::ScopedLock lock(mMutex);
198 if(mCompletedTasks.empty())
200 return RasterizingTaskPtr();
203 std::vector<RasterizingTaskPtr>::iterator next = mCompletedTasks.begin();
204 RasterizingTaskPtr nextTask = *next;
205 mCompletedTasks.erase(next);
210 void SvgRasterizeThread::RemoveTask(SvgVisual* visual)
212 // Lock while remove task from the queue
213 ConditionalWait::ScopedLock lock(mConditionalWait);
214 if(!mRasterizeTasks.empty())
216 for(std::vector<RasterizingTaskPtr>::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it)
218 if((*it) && (*it)->GetSvgVisual() == visual)
220 mRasterizeTasks.erase(it);
226 UnregisterProcessor();
229 RasterizingTaskPtr SvgRasterizeThread::NextTaskToProcess()
231 // Lock while popping task out from the queue
232 ConditionalWait::ScopedLock lock(mConditionalWait);
235 while(mRasterizeTasks.empty())
237 mIsThreadWaiting = true;
238 mConditionalWait.Wait(lock);
240 mIsThreadWaiting = false;
242 // pop out the next task from the queue
243 std::vector<RasterizingTaskPtr>::iterator next = mRasterizeTasks.begin();
244 RasterizingTaskPtr nextTask = *next;
245 mRasterizeTasks.erase(next);
250 void SvgRasterizeThread::AddCompletedTask(RasterizingTaskPtr task)
252 // Lock while adding task to the queue
253 Mutex::ScopedLock lock(mMutex);
254 mCompletedTasks.push_back(task);
256 // wake up the main thread
260 void SvgRasterizeThread::Run()
262 SetThreadName("SVGThread");
263 mLogFactory.InstallLogFunction();
265 while(RasterizingTaskPtr task = NextTaskToProcess())
269 AddCompletedTask(task);
273 void SvgRasterizeThread::ApplyRasterizedSVGToSampler()
275 while(RasterizingTaskPtr task = NextCompletedTask())
277 task->GetSvgVisual()->ApplyRasterizedImage(task->GetVectorRenderer(), task->GetPixelData(), task->IsLoaded());
280 UnregisterProcessor();
283 void SvgRasterizeThread::Process()
285 ApplyRasterizedSVGToSampler();
288 void SvgRasterizeThread::UnregisterProcessor()
290 if(mProcessorRegistered)
292 if(mRasterizeTasks.empty() && mCompletedTasks.empty())
294 Adaptor::Get().UnregisterProcessor(*this);
295 mProcessorRegistered = false;
300 } // namespace Internal
302 } // namespace Toolkit