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