Move MultiplyColorByAlpha() from main thread to resource thread
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / image-loader / image-load-thread.cpp
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include "image-load-thread.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/adaptor-framework/image-loading.h>
23 #include <dali/integration-api/adaptors/adaptor.h>
24 #include <dali/devel-api/adaptor-framework/thread-settings.h>
25
26 namespace Dali
27 {
28
29 namespace Toolkit
30 {
31
32 namespace Internal
33 {
34
35 LoadingTask::LoadingTask( uint32_t id, const VisualUrl& url, ImageDimensions dimensions,
36                           FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad )
37 : pixelBuffer(),
38   url( url ),
39   id( id ),
40   dimensions( dimensions ),
41   fittingMode( fittingMode ),
42   samplingMode( samplingMode ),
43   orientationCorrection( orientationCorrection ),
44   preMultiplyOnLoad( preMultiplyOnLoad )
45 {
46 }
47
48 void LoadingTask::Load()
49 {
50   if( url.IsLocalResource() )
51   {
52     pixelBuffer = Dali::LoadImageFromFile( url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection );
53   }
54   else
55   {
56     pixelBuffer = Dali::DownloadImageSynchronously ( url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection );
57   }
58
59   if( pixelBuffer && Pixel::HasAlpha( pixelBuffer.GetPixelFormat() ) )
60   {
61     if( preMultiplyOnLoad == DevelAsyncImageLoader::PreMultiplyOnLoad::ON )
62     {
63       pixelBuffer.MultiplyColorByAlpha();
64     }
65   }
66 }
67
68
69 ImageLoadThread::ImageLoadThread( EventThreadCallback* trigger )
70 : mTrigger( trigger ),
71   mLogFactory( Dali::Adaptor::Get().GetLogFactory() )
72 {
73 }
74
75 ImageLoadThread::~ImageLoadThread()
76 {
77   // add an empty task would stop the thread from conditional wait.
78   AddTask( NULL );
79   // stop the thread
80   Join();
81
82   delete mTrigger;
83 }
84
85 void ImageLoadThread::Run()
86 {
87   SetThreadName( "ImageLoadThread" );
88   mLogFactory.InstallLogFunction();
89
90   while( LoadingTask* task = NextTaskToProcess() )
91   {
92     task->Load();
93     AddCompletedTask( task );
94   }
95 }
96
97 void ImageLoadThread::AddTask( LoadingTask* task )
98 {
99   bool wasEmpty = false;
100
101   {
102     // Lock while adding task to the queue
103     ConditionalWait::ScopedLock lock( mConditionalWait );
104     wasEmpty = mLoadQueue.Empty();
105     mLoadQueue.PushBack( task );
106   }
107
108   if( wasEmpty )
109   {
110     // wake up the image loading thread
111     mConditionalWait.Notify();
112   }
113 }
114
115 LoadingTask* ImageLoadThread::NextCompletedTask()
116 {
117   // Lock while popping task out from the queue
118   Mutex::ScopedLock lock( mMutex );
119
120   if( mCompleteQueue.Empty() )
121   {
122     return NULL;
123   }
124
125   Vector< LoadingTask* >::Iterator next = mCompleteQueue.Begin();
126   LoadingTask* nextTask = *next;
127   mCompleteQueue.Erase( next );
128
129   return nextTask;
130 }
131
132 bool ImageLoadThread::CancelTask( uint32_t loadingTaskId )
133 {
134   // Lock while remove task from the queue
135   ConditionalWait::ScopedLock lock( mConditionalWait );
136
137   for( Vector< LoadingTask* >::Iterator iter = mLoadQueue.Begin(); iter != mLoadQueue.End(); ++iter )
138   {
139     if( (*iter)->id == loadingTaskId )
140     {
141       delete (*iter);
142       mLoadQueue.Erase( iter );
143       return true;
144     }
145   }
146
147   return false;
148 }
149
150
151 void ImageLoadThread::CancelAll()
152 {
153   // Lock while remove task from the queue
154   ConditionalWait::ScopedLock lock( mConditionalWait );
155
156   for( Vector< LoadingTask* >::Iterator iter = mLoadQueue.Begin(); iter != mLoadQueue.End(); ++iter )
157   {
158     delete ( *iter );
159   }
160   mLoadQueue.Clear();
161 }
162
163 LoadingTask* ImageLoadThread::NextTaskToProcess()
164 {
165   // Lock while popping task out from the queue
166   ConditionalWait::ScopedLock lock( mConditionalWait );
167
168   while( mLoadQueue.Empty() )
169   {
170     mConditionalWait.Wait( lock );
171   }
172
173   Vector< LoadingTask* >::Iterator next = mLoadQueue.Begin();
174   LoadingTask* nextTask = *next;
175   mLoadQueue.Erase( next );
176
177   return nextTask;
178 }
179
180 void ImageLoadThread::AddCompletedTask( LoadingTask* task )
181 {
182   // Lock while adding task to the queue
183   Mutex::ScopedLock lock( mMutex );
184   mCompleteQueue.PushBack( task );
185
186   // wake up the main thread
187   mTrigger->Trigger();
188 }
189
190 } // namespace Internal
191
192 } // namespace Toolkit
193
194 } // namespace Dali