Support YUV decoding for JPEG
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / image-loader / image-load-thread.cpp
index c1b4a91..deb0178 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 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.
 
 // EXTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/devel-api/adaptor-framework/thread-settings.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
 
 namespace Dali
 {
-
 namespace Toolkit
 {
-
 namespace Internal
 {
+LoadingTask::LoadingTask(uint32_t id, Dali::AnimatedImageLoading animatedImageLoading, uint32_t frameIndex, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
+: url(),
+  encodedImageBuffer(),
+  id(id),
+  dimensions(),
+  fittingMode(),
+  samplingMode(),
+  preMultiplyOnLoad(preMultiplyOnLoad),
+  maskPixelBuffer(),
+  contentScale(1.0f),
+  animatedImageLoading(animatedImageLoading),
+  frameIndex(frameIndex),
+  orientationCorrection(),
+  isMaskTask(false),
+  cropToMask(false),
+  loadPlanes(false)
+{
+}
+
+LoadingTask::LoadingTask(uint32_t id, const VisualUrl& url, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, bool loadPlanes)
+: url(url),
+  encodedImageBuffer(),
+  id(id),
+  dimensions(dimensions),
+  fittingMode(fittingMode),
+  samplingMode(samplingMode),
+  preMultiplyOnLoad(preMultiplyOnLoad),
+  maskPixelBuffer(),
+  contentScale(1.0f),
+  animatedImageLoading(),
+  frameIndex(0u),
+  orientationCorrection(orientationCorrection),
+  isMaskTask(false),
+  cropToMask(false),
+  loadPlanes(loadPlanes)
+{
+}
 
-LoadingTask::LoadingTask( uint32_t id, const VisualUrl& url, ImageDimensions dimensions,
-                          FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection )
-: pixelBuffer(),
-  url( url ),
-  id( id ),
-  dimensions( dimensions ),
-  fittingMode( fittingMode ),
-  samplingMode( samplingMode ),
-  orientationCorrection( orientationCorrection )
+LoadingTask::LoadingTask(uint32_t id, const EncodedImageBuffer& encodedImageBuffer, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
+: url(),
+  encodedImageBuffer(encodedImageBuffer),
+  id(id),
+  dimensions(dimensions),
+  fittingMode(fittingMode),
+  samplingMode(samplingMode),
+  preMultiplyOnLoad(preMultiplyOnLoad),
+  maskPixelBuffer(),
+  contentScale(1.0f),
+  animatedImageLoading(),
+  frameIndex(0u),
+  orientationCorrection(orientationCorrection),
+  isMaskTask(false),
+  cropToMask(false),
+  loadPlanes(false)
 {
 }
 
+LoadingTask::LoadingTask(uint32_t id, Devel::PixelBuffer pixelBuffer, Devel::PixelBuffer maskPixelBuffer, float contentScale, bool cropToMask, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
+: url(""),
+  encodedImageBuffer(),
+  id(id),
+  dimensions(),
+  fittingMode(),
+  samplingMode(),
+  preMultiplyOnLoad(preMultiplyOnLoad),
+  maskPixelBuffer(maskPixelBuffer),
+  contentScale(contentScale),
+  animatedImageLoading(),
+  frameIndex(0u),
+  orientationCorrection(),
+  isMaskTask(true),
+  cropToMask(cropToMask),
+  loadPlanes(false)
+{
+  pixelBuffers.push_back(pixelBuffer);
+}
+
 void LoadingTask::Load()
 {
-  if( url.IsLocal() )
+  Devel::PixelBuffer pixelBuffer;
+  if(animatedImageLoading)
+  {
+    pixelBuffer = animatedImageLoading.LoadFrame(frameIndex);
+  }
+  else if(encodedImageBuffer)
+  {
+    pixelBuffer = Dali::LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), dimensions, fittingMode, samplingMode, orientationCorrection);
+  }
+  else if(url.IsValid() && url.IsLocalResource())
+  {
+    if(loadPlanes)
+    {
+      Dali::LoadImagePlanesFromFile(url.GetUrl(), pixelBuffers, dimensions, fittingMode, samplingMode, orientationCorrection);
+    }
+    else
+    {
+      pixelBuffer = Dali::LoadImageFromFile(url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection);
+    }
+  }
+  else if(url.IsValid())
+  {
+    pixelBuffer = Dali::DownloadImageSynchronously(url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection);
+  }
+
+  if(pixelBuffer)
+  {
+    pixelBuffers.push_back(pixelBuffer);
+  }
+
+  if(pixelBuffers.empty())
   {
-    pixelBuffer = Dali::LoadImageFromFile( url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection );
+    DALI_LOG_ERROR("LoadingTask::Load: Loading is failed: %s\n", url.GetUrl().c_str());
   }
-  else
+}
+
+void LoadingTask::ApplyMask()
+{
+  if(!pixelBuffers.empty())
   {
-    pixelBuffer = Dali::DownloadImageSynchronously ( url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection );
+    pixelBuffers[0].ApplyMask(maskPixelBuffer, contentScale, cropToMask);
   }
 }
 
+void LoadingTask::MultiplyAlpha()
+{
+  if(!pixelBuffers.empty() && Pixel::HasAlpha(pixelBuffers[0].GetPixelFormat()))
+  {
+    if(preMultiplyOnLoad == DevelAsyncImageLoader::PreMultiplyOnLoad::ON)
+    {
+      pixelBuffers[0].MultiplyColorByAlpha();
+    }
+  }
+}
 
-ImageLoadThread::ImageLoadThread( EventThreadCallback* trigger )
-: mTrigger( trigger )
+ImageLoadThread::ImageLoadThread(EventThreadCallback* trigger)
+: mTrigger(trigger),
+  mLogFactory(Dali::Adaptor::Get().GetLogFactory())
 {
 }
 
 ImageLoadThread::~ImageLoadThread()
 {
   // add an empty task would stop the thread from conditional wait.
-  AddTask( NULL );
+  AddTask(NULL);
   // stop the thread
   Join();
 
   delete mTrigger;
+
+  for(auto&& iter : mLoadQueue)
+  {
+    delete iter;
+  }
+  mLoadQueue.Clear();
+
+  for(auto&& iter : mCompleteQueue)
+  {
+    delete iter;
+  }
+  mCompleteQueue.Clear();
 }
 
 void ImageLoadThread::Run()
 {
-  while( LoadingTask* task = NextTaskToProcess() )
+  SetThreadName("ImageLoadThread");
+  mLogFactory.InstallLogFunction();
+
+  while(LoadingTask* task = NextTaskToProcess())
   {
-    task->Load();
-    AddCompletedTask( task );
+    if(!task->isMaskTask)
+    {
+      task->Load();
+    }
+    else
+    {
+      task->ApplyMask();
+    }
+    task->MultiplyAlpha();
+
+    AddCompletedTask(task);
   }
 }
 
-void ImageLoadThread::AddTask( LoadingTask* task )
+void ImageLoadThread::AddTask(LoadingTask* task)
 {
   bool wasEmpty = false;
-
   {
     // Lock while adding task to the queue
-    ConditionalWait::ScopedLock lock( mConditionalWait );
+    ConditionalWait::ScopedLock lock(mConditionalWait);
     wasEmpty = mLoadQueue.Empty();
-    mLoadQueue.PushBack( task );
+    mLoadQueue.PushBack(task);
   }
 
-  if( wasEmpty )
+  if(wasEmpty)
   {
     // wake up the image loading thread
     mConditionalWait.Notify();
@@ -100,31 +234,31 @@ void ImageLoadThread::AddTask( LoadingTask* task )
 LoadingTask* ImageLoadThread::NextCompletedTask()
 {
   // Lock while popping task out from the queue
-  Mutex::ScopedLock lock( mMutex );
+  Mutex::ScopedLock lock(mMutex);
 
-  if( mCompleteQueue.Empty() )
+  if(mCompleteQueue.Empty())
   {
     return NULL;
   }
 
-  Vector< LoadingTask* >::Iterator next = mCompleteQueue.Begin();
-  LoadingTask* nextTask = *next;
-  mCompleteQueue.Erase( next );
+  Vector<LoadingTask*>::Iterator next     = mCompleteQueue.Begin();
+  LoadingTask*                   nextTask = *next;
+  mCompleteQueue.Erase(next);
 
   return nextTask;
 }
 
-bool ImageLoadThread::CancelTask( uint32_t loadingTaskId )
+bool ImageLoadThread::CancelTask(uint32_t loadingTaskId)
 {
   // Lock while remove task from the queue
-  ConditionalWait::ScopedLock lock( mConditionalWait );
+  ConditionalWait::ScopedLock lock(mConditionalWait);
 
-  for( Vector< LoadingTask* >::Iterator iter = mLoadQueue.Begin(); iter != mLoadQueue.End(); ++iter )
+  for(Vector<LoadingTask*>::Iterator iter = mLoadQueue.Begin(); iter != mLoadQueue.End(); ++iter)
   {
-    if( (*iter)->id == loadingTaskId )
+    if((*iter)->id == loadingTaskId)
     {
-      delete (*iter);
-      mLoadQueue.Erase( iter );
+      delete(*iter);
+      mLoadQueue.Erase(iter);
       return true;
     }
   }
@@ -132,15 +266,14 @@ bool ImageLoadThread::CancelTask( uint32_t loadingTaskId )
   return false;
 }
 
-
 void ImageLoadThread::CancelAll()
 {
   // Lock while remove task from the queue
-  ConditionalWait::ScopedLock lock( mConditionalWait );
+  ConditionalWait::ScopedLock lock(mConditionalWait);
 
-  for( Vector< LoadingTask* >::Iterator iter = mLoadQueue.Begin(); iter != mLoadQueue.End(); ++iter )
+  for(Vector<LoadingTask*>::Iterator iter = mLoadQueue.Begin(); iter != mLoadQueue.End(); ++iter)
   {
-    delete ( *iter );
+    delete(*iter);
   }
   mLoadQueue.Clear();
 }
@@ -148,25 +281,25 @@ void ImageLoadThread::CancelAll()
 LoadingTask* ImageLoadThread::NextTaskToProcess()
 {
   // Lock while popping task out from the queue
-  ConditionalWait::ScopedLock lock( mConditionalWait );
+  ConditionalWait::ScopedLock lock(mConditionalWait);
 
-  while( mLoadQueue.Empty() )
+  while(mLoadQueue.Empty())
   {
-    mConditionalWait.Wait( lock );
+    mConditionalWait.Wait(lock);
   }
 
-  Vector< LoadingTask* >::Iterator next = mLoadQueue.Begin();
-  LoadingTask* nextTask = *next;
-  mLoadQueue.Erase( next );
+  Vector<LoadingTask*>::Iterator next     = mLoadQueue.Begin();
+  LoadingTask*                   nextTask = *next;
+  mLoadQueue.Erase(next);
 
   return nextTask;
 }
 
-void ImageLoadThread::AddCompletedTask( LoadingTask* task )
+void ImageLoadThread::AddCompletedTask(LoadingTask* task)
 {
   // Lock while adding task to the queue
-  Mutex::ScopedLock lock( mMutex );
-  mCompleteQueue.PushBack( task );
+  Mutex::ScopedLock lock(mMutex);
+  mCompleteQueue.PushBack(task);
 
   // wake up the main thread
   mTrigger->Trigger();