179734a10671b19aaf3a5eba27d4f51381ff04cc
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / image-loader / image-load-thread.cpp
1 /*
2  * Copyright (c) 2019 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/devel-api/adaptor-framework/thread-settings.h>
24 #include <dali/integration-api/adaptor-framework/adaptor.h>
25 #include <dali/integration-api/debug.h>
26
27 namespace Dali
28 {
29
30 namespace Toolkit
31 {
32
33 namespace Internal
34 {
35
36 LoadingTask::LoadingTask( uint32_t id, const VisualUrl& url, ImageDimensions dimensions,
37                           FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad )
38 : pixelBuffer(),
39   url( url ),
40   id( id ),
41   dimensions( dimensions ),
42   fittingMode( fittingMode ),
43   samplingMode( samplingMode ),
44   orientationCorrection( orientationCorrection ),
45   preMultiplyOnLoad( preMultiplyOnLoad ),
46   isMaskTask( false ),
47   maskPixelBuffer(),
48   contentScale( 1.0f ),
49   cropToMask( false )
50 {
51 }
52
53 LoadingTask::LoadingTask( uint32_t id, Devel::PixelBuffer pixelBuffer, Devel::PixelBuffer maskPixelBuffer, float contentScale, bool cropToMask,
54                           DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad )
55 : pixelBuffer( pixelBuffer ),
56   url( "" ),
57   id( id ),
58   dimensions(),
59   fittingMode(),
60   samplingMode(),
61   orientationCorrection(),
62   preMultiplyOnLoad( preMultiplyOnLoad ),
63   isMaskTask( true ),
64   maskPixelBuffer( maskPixelBuffer ),
65   contentScale( contentScale ),
66   cropToMask( cropToMask )
67 {
68 }
69
70 void LoadingTask::Load()
71 {
72   if( url.IsLocalResource() )
73   {
74     pixelBuffer = Dali::LoadImageFromFile( url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection );
75   }
76   else
77   {
78     pixelBuffer = Dali::DownloadImageSynchronously ( url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection );
79   }
80
81   if( !pixelBuffer )
82   {
83     DALI_LOG_ERROR( "LoadingTask::Load: Loading is failed: %s\n", url.GetUrl().c_str() );
84   }
85 }
86
87 void LoadingTask::ApplyMask()
88 {
89   pixelBuffer.ApplyMask( maskPixelBuffer, contentScale, cropToMask );
90 }
91
92 void LoadingTask::MultiplyAlpha()
93 {
94   if( pixelBuffer && Pixel::HasAlpha( pixelBuffer.GetPixelFormat() ) )
95   {
96     if( preMultiplyOnLoad == DevelAsyncImageLoader::PreMultiplyOnLoad::ON )
97     {
98       pixelBuffer.MultiplyColorByAlpha();
99     }
100   }
101 }
102
103 ImageLoadThread::ImageLoadThread( EventThreadCallback* trigger )
104 : mTrigger( trigger ),
105   mLogFactory( Dali::Adaptor::Get().GetLogFactory() )
106 {
107 }
108
109 ImageLoadThread::~ImageLoadThread()
110 {
111   // add an empty task would stop the thread from conditional wait.
112   AddTask( NULL );
113   // stop the thread
114   Join();
115
116   delete mTrigger;
117 }
118
119 void ImageLoadThread::Run()
120 {
121   SetThreadName( "ImageLoadThread" );
122   mLogFactory.InstallLogFunction();
123
124   while( LoadingTask* task = NextTaskToProcess() )
125   {
126     if( !task->isMaskTask )
127     {
128       task->Load();
129     }
130     else
131     {
132       task->ApplyMask();
133     }
134     task->MultiplyAlpha();
135
136     AddCompletedTask( task );
137   }
138 }
139
140 void ImageLoadThread::AddTask( LoadingTask* task )
141 {
142   bool wasEmpty = false;
143
144   {
145     // Lock while adding task to the queue
146     ConditionalWait::ScopedLock lock( mConditionalWait );
147     wasEmpty = mLoadQueue.Empty();
148     mLoadQueue.PushBack( task );
149   }
150
151   if( wasEmpty )
152   {
153     // wake up the image loading thread
154     mConditionalWait.Notify();
155   }
156 }
157
158 LoadingTask* ImageLoadThread::NextCompletedTask()
159 {
160   // Lock while popping task out from the queue
161   Mutex::ScopedLock lock( mMutex );
162
163   if( mCompleteQueue.Empty() )
164   {
165     return NULL;
166   }
167
168   Vector< LoadingTask* >::Iterator next = mCompleteQueue.Begin();
169   LoadingTask* nextTask = *next;
170   mCompleteQueue.Erase( next );
171
172   return nextTask;
173 }
174
175 bool ImageLoadThread::CancelTask( uint32_t loadingTaskId )
176 {
177   // Lock while remove task from the queue
178   ConditionalWait::ScopedLock lock( mConditionalWait );
179
180   for( Vector< LoadingTask* >::Iterator iter = mLoadQueue.Begin(); iter != mLoadQueue.End(); ++iter )
181   {
182     if( (*iter)->id == loadingTaskId )
183     {
184       delete (*iter);
185       mLoadQueue.Erase( iter );
186       return true;
187     }
188   }
189
190   return false;
191 }
192
193
194 void ImageLoadThread::CancelAll()
195 {
196   // Lock while remove task from the queue
197   ConditionalWait::ScopedLock lock( mConditionalWait );
198
199   for( Vector< LoadingTask* >::Iterator iter = mLoadQueue.Begin(); iter != mLoadQueue.End(); ++iter )
200   {
201     delete ( *iter );
202   }
203   mLoadQueue.Clear();
204 }
205
206 LoadingTask* ImageLoadThread::NextTaskToProcess()
207 {
208   // Lock while popping task out from the queue
209   ConditionalWait::ScopedLock lock( mConditionalWait );
210
211   while( mLoadQueue.Empty() )
212   {
213     mConditionalWait.Wait( lock );
214   }
215
216   Vector< LoadingTask* >::Iterator next = mLoadQueue.Begin();
217   LoadingTask* nextTask = *next;
218   mLoadQueue.Erase( next );
219
220   return nextTask;
221 }
222
223 void ImageLoadThread::AddCompletedTask( LoadingTask* task )
224 {
225   // Lock while adding task to the queue
226   Mutex::ScopedLock lock( mMutex );
227   mCompleteQueue.PushBack( task );
228
229   // wake up the main thread
230   mTrigger->Trigger();
231 }
232
233 } // namespace Internal
234
235 } // namespace Toolkit
236
237 } // namespace Dali