X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fvisuals%2Fsvg%2Fsvg-rasterize-thread.cpp;h=c6e0a2c23f7d092cf2b7b78dfd6f5bc06deb4189;hp=151eda857d6e029651dfe75f717412c755c45bc8;hb=e8a53a0a591085c6b7470feac4f9cea85cc8ae6e;hpb=52f63e08e4386ce4f33bf03a34e6f039364a4064 diff --git a/dali-toolkit/internal/visuals/svg/svg-rasterize-thread.cpp b/dali-toolkit/internal/visuals/svg/svg-rasterize-thread.cpp index 151eda8..c6e0a2c 100644 --- a/dali-toolkit/internal/visuals/svg/svg-rasterize-thread.cpp +++ b/dali-toolkit/internal/visuals/svg/svg-rasterize-thread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,201 +19,149 @@ #include "svg-rasterize-thread.h" // EXTERNAL INCLUDES -#include #include +#include +#include #include // INTERNAL INCLUDES -#ifdef NO_THORVG -#include -#endif /* NO_THORVG */ #include namespace Dali { - namespace Toolkit { - namespace Internal { +SvgTask::SvgTask(SvgVisual* svgVisual, VectorImageRenderer vectorRenderer) +: mSvgVisual(svgVisual), + mVectorRenderer(vectorRenderer), + mHasSucceeded(false) +{ +} -namespace +SvgVisual* SvgTask::GetSvgVisual() const { -const char * const UNITS("px"); + return mSvgVisual.Get(); } -#ifdef NO_THORVG -RasterizingTask::RasterizingTask( SvgVisual* svgRenderer, NSVGimage* parsedSvg, const VisualUrl& url, float dpi, unsigned int width, unsigned int height) -: mSvgVisual( svgRenderer ), - mParsedSvg( parsedSvg ), - mUrl( url ), - mDpi( dpi ), - mWidth( width ), - mHeight( height ) +PixelData SvgTask::GetPixelData() const { - mRasterizer = nsvgCreateRasterizer(); + return PixelData(); } -#else /* NO_THORVG */ -RasterizingTask::RasterizingTask( SvgVisual* svgRenderer, VectorImageRenderer vectorRenderer, const VisualUrl& url, float dpi, unsigned int width, unsigned int height, bool loaded) -: mSvgVisual( svgRenderer ), - mVectorRenderer( vectorRenderer ), - mUrl( url ), - mDpi( dpi ), - mWidth( width ), - mHeight( height ), - mLoaded( loaded ) + +bool SvgTask::HasSucceeded() const { + return mHasSucceeded; +} +SvgLoadingTask::SvgLoadingTask(SvgVisual* svgVisual, VectorImageRenderer vectorRenderer, const VisualUrl& url, float dpi) +: SvgTask(svgVisual, vectorRenderer), + mUrl(url), + mDpi(dpi) +{ } -#endif /* NO_THORVG */ -RasterizingTask::~RasterizingTask() +SvgLoadingTask::~SvgLoadingTask() { -#ifdef NO_THORVG - nsvgDeleteRasterizer( mRasterizer ); -#endif /* NO_THORVG */ } -void RasterizingTask::Load() +void SvgLoadingTask::Process() { -#ifdef NO_THORVG - if( mParsedSvg != NULL) + if(mVectorRenderer.IsLoaded()) { + // Already loaded + mHasSucceeded = true; return; } - if( !mUrl.IsLocalResource() ) - { - Dali::Vector remoteBuffer; + Dali::Vector buffer; - if( !Dali::FileLoader::DownloadFileSynchronously( mUrl.GetUrl(), remoteBuffer )) + if(!mUrl.IsLocalResource()) + { + if(!Dali::FileLoader::DownloadFileSynchronously(mUrl.GetUrl(), buffer)) { - DALI_LOG_ERROR("Failed to download file!\n"); + DALI_LOG_ERROR("Failed to download file! [%s]\n", mUrl.GetUrl().c_str()); return; } - - remoteBuffer.PushBack( '\0' ); - mParsedSvg = nsvgParse( reinterpret_cast(remoteBuffer.begin()), UNITS, mDpi ); } -#else /* NO_THORVG */ - if( !mLoaded && !mUrl.IsLocalResource() ) + else { - Dali::Vector remoteBuffer; - - if( !Dali::FileLoader::DownloadFileSynchronously( mUrl.GetUrl(), remoteBuffer )) + if(!Dali::FileLoader::ReadFile(mUrl.GetUrl(), buffer)) { - DALI_LOG_ERROR("Failed to download file!\n"); + DALI_LOG_ERROR("Failed to read file! [%s]\n", mUrl.GetUrl().c_str()); return; } - - remoteBuffer.PushBack( '\0' ); - char *data = reinterpret_cast(remoteBuffer.begin()); - if ( !mVectorRenderer.Load( data, remoteBuffer.Size())) - { - DALI_LOG_ERROR( "Failed to load data!\n" ); - return; - } - - mLoaded = true; } -#endif /* NO_THORVG */ -} -void RasterizingTask::Rasterize( ) -{ -#ifdef NO_THORVG - if( mParsedSvg != NULL && mWidth > 0u && mHeight > 0u ) - { - float scaleX = static_cast( mWidth ) / mParsedSvg->width; - float scaleY = static_cast( mHeight ) / mParsedSvg->height; - float scale = scaleX < scaleY ? scaleX : scaleY; - unsigned int bufferStride = mWidth*Pixel::GetBytesPerPixel( Pixel::RGBA8888 ); - unsigned int bufferSize = bufferStride * mHeight; - - unsigned char* buffer = new unsigned char [bufferSize]; - nsvgRasterize(mRasterizer, mParsedSvg, 0.f,0.f,scale, - buffer, mWidth, mHeight, - bufferStride ); - - mPixelData = Dali::PixelData::New( buffer, bufferSize, mWidth, mHeight, Pixel::RGBA8888, Dali::PixelData::DELETE_ARRAY ); - } -#else /* NO_THORVG */ - if ( mWidth <= 0u || mHeight <= 0u ) + buffer.PushBack('\0'); + + if(!mVectorRenderer.Load(buffer, mDpi)) { - DALI_LOG_ERROR( "Size is zero!\n" ); + DALI_LOG_ERROR("Failed to load data! [%s]\n", mUrl.GetUrl().c_str()); return; } - Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New( mWidth, mHeight, Dali::Pixel::RGBA8888 ); - mVectorRenderer.SetBuffer( pixelBuffer ); - { - uint32_t defaultWidth, defaultHeight; - mVectorRenderer.GetDefaultSize( defaultWidth, defaultHeight ); - - float scaleX = static_cast( mWidth ) / static_cast( defaultWidth ); - float scaleY = static_cast( mHeight ) / static_cast( defaultHeight ); - float scale = scaleX < scaleY ? scaleX : scaleY; - - if ( !mVectorRenderer.Render( scale ) ) - { - DALI_LOG_ERROR( "SVG Render Fail!\n" ); - return; - } - - mPixelData = Devel::PixelBuffer::Convert( pixelBuffer ); - if ( !mPixelData ) - { - DALI_LOG_ERROR( "Pixel Data is null\n" ); - } - } -#endif /* NO_THORVG */ + mHasSucceeded = true; } -#ifdef NO_THORVG -NSVGimage* RasterizingTask::GetParsedImage() const -{ - return mParsedSvg; -} -#else /* NO_THORVG */ -VectorImageRenderer RasterizingTask::GetVectorRenderer() const +SvgRasterizingTask::SvgRasterizingTask(SvgVisual* svgVisual, VectorImageRenderer vectorRenderer, unsigned int width, unsigned int height) +: SvgTask(svgVisual, vectorRenderer), + mWidth(width), + mHeight(height) { - return mVectorRenderer; } -bool RasterizingTask::IsLoaded() const +SvgRasterizingTask::~SvgRasterizingTask() { - return mLoaded; } -#endif /* NO_THORVG */ -SvgVisual* RasterizingTask::GetSvgVisual() const +void SvgRasterizingTask::Process() { - return mSvgVisual.Get(); + if(!mVectorRenderer.IsLoaded()) + { + DALI_LOG_ERROR("File is not loaded!\n"); + return; + } + + Devel::PixelBuffer pixelBuffer = mVectorRenderer.Rasterize(mWidth, mHeight); + if(!pixelBuffer) + { + DALI_LOG_ERROR("Rasterize is failed!\n"); + return; + } + + mPixelData = Devel::PixelBuffer::Convert(pixelBuffer); + mHasSucceeded = true; } -PixelData RasterizingTask::GetPixelData() const +PixelData SvgRasterizingTask::GetPixelData() const { return mPixelData; } -SvgRasterizeThread::SvgRasterizeThread( EventThreadCallback* trigger ) -: mTrigger( trigger ), - mIsThreadWaiting( false ) +SvgRasterizeThread::SvgRasterizeThread() +: mTrigger(new EventThreadCallback(MakeCallback(this, &SvgRasterizeThread::ApplyRasterizedSVGToSampler))), + mLogFactory(Dali::Adaptor::Get().GetLogFactory()), + mIsThreadWaiting(false), + mProcessorRegistered(false) { } SvgRasterizeThread::~SvgRasterizeThread() { - delete mTrigger; + if(mProcessorRegistered) + { + Adaptor::Get().UnregisterProcessor(*this); + } } -void SvgRasterizeThread::TerminateThread( SvgRasterizeThread*& thread ) +void SvgRasterizeThread::TerminateThread(SvgRasterizeThread*& thread) { - if( thread ) + if(thread) { // add an empty task would stop the thread from conditional wait. - thread->AddTask( RasterizingTaskPtr() ); + thread->AddTask(SvgTaskPtr()); // stop the thread thread->Join(); // delete the thread @@ -222,143 +170,110 @@ void SvgRasterizeThread::TerminateThread( SvgRasterizeThread*& thread ) } } -void SvgRasterizeThread::AddTask( RasterizingTaskPtr task ) +void SvgRasterizeThread::AddTask(SvgTaskPtr task) { bool wasEmpty = false; { // Lock while adding task to the queue - ConditionalWait::ScopedLock lock( mConditionalWait ); + ConditionalWait::ScopedLock lock(mConditionalWait); wasEmpty = mRasterizeTasks.empty(); - if( !wasEmpty && task != NULL) + if(!wasEmpty && task) { // Remove the tasks with the same renderer. // Older task which waiting to rasterize and apply the svg to the same renderer is expired. - for( std::vector< RasterizingTaskPtr >::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it ) + // Rasterizing task only, loading task is not duplicated. + for(std::vector::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it) { - if( (*it) && (*it)->GetSvgVisual() == task->GetSvgVisual() ) + if((*it) && (*it)->GetSvgVisual() == task->GetSvgVisual()) { - mRasterizeTasks.erase( it ); - break; + SvgRasterizingTask* oldTask = dynamic_cast(it->Get()); + SvgRasterizingTask* newTask = dynamic_cast(task.Get()); + if(oldTask && newTask) + { + mRasterizeTasks.erase(it); + break; + } } } } - mRasterizeTasks.push_back( task ); + mRasterizeTasks.push_back(task); + + if(!mProcessorRegistered) + { + Adaptor::Get().RegisterProcessor(*this); + mProcessorRegistered = true; + } } - if( wasEmpty) + if(wasEmpty) { // wake up the image loading thread mConditionalWait.Notify(); } } -RasterizingTaskPtr SvgRasterizeThread::NextCompletedTask() +SvgTaskPtr SvgRasterizeThread::NextCompletedTask() { // Lock while popping task out from the queue - Mutex::ScopedLock lock( mMutex ); + Mutex::ScopedLock lock(mMutex); - if( mCompletedTasks.empty() ) + if(mCompletedTasks.empty()) { - return RasterizingTaskPtr(); + return SvgTaskPtr(); } - std::vector< RasterizingTaskPtr >::iterator next = mCompletedTasks.begin(); - RasterizingTaskPtr nextTask = *next; - mCompletedTasks.erase( next ); + std::vector::iterator next = mCompletedTasks.begin(); + SvgTaskPtr nextTask = *next; + mCompletedTasks.erase(next); return nextTask; } -void SvgRasterizeThread::RemoveTask( SvgVisual* visual ) +void SvgRasterizeThread::RemoveTask(SvgVisual* visual) { // Lock while remove task from the queue - ConditionalWait::ScopedLock lock( mConditionalWait ); - if( !mRasterizeTasks.empty() ) + ConditionalWait::ScopedLock lock(mConditionalWait); + if(!mRasterizeTasks.empty()) { - for( std::vector< RasterizingTaskPtr >::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it ) + for(std::vector::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it) { - if( (*it) && (*it)->GetSvgVisual() == visual ) + if((*it) && (*it)->GetSvgVisual() == visual) { - mRasterizeTasks.erase( it ); - break; + mRasterizeTasks.erase(it); } } } -} - -#ifdef NO_THORVG -void SvgRasterizeThread::DeleteImage( NSVGimage* parsedSvg ) -{ - // Lock while adding image to the delete queue - ConditionalWait::ScopedLock lock( mConditionalWait ); - - if( mIsThreadWaiting ) // no rasterization is ongoing, save to delete - { - nsvgDelete( parsedSvg ); - } - else // wait to delete until current rasterization completed. - { - mDeleteSvg.PushBack( parsedSvg ); - } -} -#else /* NO_THORVG */ -void SvgRasterizeThread::DeleteImage( VectorImageRenderer vectorRenderer ) -{ - // Lock while adding image to the delete queue - ConditionalWait::ScopedLock lock( mConditionalWait ); - if( mIsThreadWaiting ) // no rasterization is ongoing, save to delete - { - // TODO: what? - } - else // wait to delete until current rasterization completed. - { - mDeleteSvg.PushBack( &vectorRenderer ); - } + UnregisterProcessor(); } -#endif /* NO_THORVG */ -RasterizingTaskPtr SvgRasterizeThread::NextTaskToProcess() +SvgTaskPtr SvgRasterizeThread::NextTaskToProcess() { // Lock while popping task out from the queue - ConditionalWait::ScopedLock lock( mConditionalWait ); - - // Delete the image here to make sure that it is not used in the nsvgRasterize() - if( !mDeleteSvg.Empty() ) - { -#ifdef NO_THORVG - for( Vector< NSVGimage* >::Iterator it = mDeleteSvg.Begin(), endIt = mDeleteSvg.End(); - it != endIt; - ++it ) - { - nsvgDelete( *it ); - } -#endif /* NO_THORVG */ - mDeleteSvg.Clear(); - } + ConditionalWait::ScopedLock lock(mConditionalWait); // conditional wait - while( mRasterizeTasks.empty() ) + while(mRasterizeTasks.empty()) { mIsThreadWaiting = true; - mConditionalWait.Wait( lock ); + mConditionalWait.Wait(lock); } mIsThreadWaiting = false; // pop out the next task from the queue - std::vector< RasterizingTaskPtr >::iterator next = mRasterizeTasks.begin(); - RasterizingTaskPtr nextTask = *next; - mRasterizeTasks.erase( next ); + std::vector::iterator next = mRasterizeTasks.begin(); + SvgTaskPtr nextTask = *next; + mRasterizeTasks.erase(next); return nextTask; } -void SvgRasterizeThread::AddCompletedTask( RasterizingTaskPtr task ) +void SvgRasterizeThread::AddCompletedTask(SvgTaskPtr task) { // Lock while adding task to the queue - Mutex::ScopedLock lock( mMutex ); - mCompletedTasks.push_back( task ); + Mutex::ScopedLock lock(mMutex); + mCompletedTasks.push_back(task); // wake up the main thread mTrigger->Trigger(); @@ -366,12 +281,40 @@ void SvgRasterizeThread::AddCompletedTask( RasterizingTaskPtr task ) void SvgRasterizeThread::Run() { - SetThreadName( "SVGThread" ); - while( RasterizingTaskPtr task = NextTaskToProcess() ) + SetThreadName("SVGThread"); + mLogFactory.InstallLogFunction(); + + while(SvgTaskPtr task = NextTaskToProcess()) { - task->Load( ); - task->Rasterize( ); - AddCompletedTask( task ); + task->Process(); + AddCompletedTask(task); + } +} + +void SvgRasterizeThread::ApplyRasterizedSVGToSampler() +{ + while(SvgTaskPtr task = NextCompletedTask()) + { + task->GetSvgVisual()->ApplyRasterizedImage(task->GetPixelData(), task->HasSucceeded()); + } + + UnregisterProcessor(); +} + +void SvgRasterizeThread::Process(bool postProcessor) +{ + ApplyRasterizedSVGToSampler(); +} + +void SvgRasterizeThread::UnregisterProcessor() +{ + if(mProcessorRegistered) + { + if(mRasterizeTasks.empty() && mCompletedTasks.empty()) + { + Adaptor::Get().UnregisterProcessor(*this); + mProcessorRegistered = false; + } } }