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