(Images) Reducing thread tennis
[platform/core/uifw/dali-core.git] / dali / internal / event / images / image-impl.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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 // CLASS HEADER
18 #include <dali/internal/event/images/image-impl.h>
19
20 // INTERNAL INCLUDES
21 #include <dali/public-api/common/dali-common.h>
22
23 #include <dali/integration-api/platform-abstraction.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/internal/event/resources/resource-ticket.h>
26 #include <dali/internal/event/common/thread-local-storage.h>
27 #include <dali/internal/event/resources/resource-client.h>
28 #include <dali/internal/event/images/image-factory.h>
29 #include <dali/internal/event/common/stage-impl.h>
30
31 using namespace Dali::Integration;
32
33 namespace Dali
34 {
35
36 namespace Internal
37 {
38
39 Image::Image( LoadPolicy loadPol, ReleasePolicy releasePol )
40 : mWidth(0),
41   mHeight(0),
42   mLoadPolicy(loadPol),
43   mReleasePolicy(releasePol),
44   mConnectionCount(0),
45   mImageFactory(ThreadLocalStorage::Get().GetImageFactory())
46 {
47 }
48
49 Image* Image::New()
50 {
51   return new Image;
52 }
53
54 Image* Image::New( const std::string& filename, LoadPolicy loadPol, ReleasePolicy releasePol )
55 {
56   Image* image = new Image( loadPol, releasePol );
57
58   image->mRequest = image->mImageFactory.RegisterRequest( filename, NULL );
59
60   if( ! filename.empty() )
61   {
62     Vector2 size;
63     Internal::ThreadLocalStorage::Get().GetPlatformAbstraction().LoadImageMetadata( filename, size );
64     image->mWidth = (int)size.width;
65     image->mHeight = (int)size.height;
66   }
67
68   if( Dali::Image::OnDemand == loadPol )
69   {
70     // load image on demand,
71     // ask for ticket on connect
72   }
73   else
74   {
75     // load image immediately
76     image->mTicket = image->mImageFactory.Load( image->mRequest.Get() );
77     image->mTicket->AddObserver( *image );
78   }
79
80   DALI_LOG_SET_OBJECT_STRING( image, filename );
81
82   return image;
83 }
84
85 Image* Image::New( const std::string& filename, const Dali::ImageAttributes& attributes, LoadPolicy loadPol, ReleasePolicy releasePol )
86 {
87   Image* image = new Image( loadPol, releasePol );
88
89   if( ! filename.empty() )
90   {
91     if( attributes.GetWidth() == 0 && attributes.GetHeight() == 0 )
92     {
93       // Only get actual file size if a requested size is not present.
94       Vector2 size;
95       Internal::ThreadLocalStorage::Get().GetPlatformAbstraction().LoadImageMetadata( filename, size );
96       image->mWidth = (int)size.width;
97       image->mHeight = (int)size.height;
98     }
99     // @TODO: else, determine closest size to requested size
100   }
101
102   image->mRequest = image->mImageFactory.RegisterRequest( filename, &attributes );
103
104   // Lazily load image data later, only when it is needed to draw something:
105   if( Dali::Image::OnDemand == loadPol )
106   {
107     // Ask for ticket later, only on connect.
108   }
109   else
110   {
111     // Trigger loading of the image over on a resource thread eagerly as soon as it
112     // can be scheduled:
113     image->mTicket = image->mImageFactory.Load( image->mRequest.Get() );
114     image->mTicket->AddObserver( *image );
115   }
116
117   DALI_LOG_SET_OBJECT_STRING( image, filename );
118
119   return image;
120 }
121
122 Image* Image::New( NativeImage& nativeImg, LoadPolicy loadPol, ReleasePolicy releasePol )
123 {
124   Image* image = new Image;
125   ResourceClient &resourceClient = ThreadLocalStorage::Get().GetResourceClient();
126
127
128   image->mWidth  = nativeImg.GetWidth();
129   image->mHeight = nativeImg.GetHeight();
130
131   const ResourceTicketPtr& ticket = resourceClient.AddNativeImage( nativeImg );
132   DALI_ASSERT_DEBUG( dynamic_cast<ImageTicket*>( ticket.Get() ) && "Resource ticket not ImageTicket subclass for image resource.\n" );
133   image->mTicket = static_cast<ImageTicket*>(ticket.Get());
134   image->mTicket->AddObserver( *image );
135
136   return image;
137 }
138
139 Image::~Image()
140 {
141   if( mTicket )
142   {
143     mTicket->RemoveObserver( *this );
144     if( Stage::IsInstalled() )
145     {
146       mImageFactory.ReleaseTicket( mTicket.Get() );
147     }
148   }
149 }
150
151 bool Image::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
152 {
153   bool connected( true );
154   DALI_ASSERT_DEBUG( dynamic_cast<Image*>( object ) && "Resource ticket not ImageTicket subclass for image resource.\n" );
155   Image* image = static_cast<Image*>(object);
156
157   if( Dali::Image::SIGNAL_IMAGE_LOADING_FINISHED == signalName )
158   {
159     image->LoadingFinishedSignal().Connect( tracker, functor );
160   }
161   else if(Dali::Image::SIGNAL_IMAGE_UPLOADED == signalName)
162   {
163     image->UploadedSignal().Connect( tracker, functor );
164   }
165   else
166   {
167     // signalName does not match any signal
168     connected = false;
169   }
170
171   return connected;
172 }
173
174 ResourceId Image::GetResourceId() const
175 {
176   ResourceId ret = mTicket ? mTicket->GetId() : 0;
177
178   return ret;
179 }
180
181 const Dali::ImageAttributes& Image::GetAttributes() const
182 {
183   if( mTicket )
184   {
185     return mImageFactory.GetActualAttributes( mTicket->GetId() );
186   }
187   else
188   {
189     return mImageFactory.GetRequestAttributes( mRequest.Get() );
190   }
191 }
192
193 const std::string& Image::GetFilename() const
194 {
195   return mImageFactory.GetRequestPath( mRequest.Get() );
196 }
197
198 void Image::Reload()
199 {
200   if ( mRequest )
201   {
202     ResourceTicketPtr ticket = mImageFactory.Reload( mRequest.Get() );
203     SetTicket( ticket.Get() );
204   }
205 }
206
207 void Image::ResourceLoadingFailed(const ResourceTicket& ticket)
208 {
209   mLoadingFinishedV2.Emit( Dali::Image( this ) );
210 }
211
212 void Image::ResourceLoadingSucceeded(const ResourceTicket& ticket)
213 {
214   // Update size with actual loaded size
215   const ImageTicket* imageTicket = static_cast<const ImageTicket*>(&ticket);
216   mWidth = imageTicket->GetWidth();
217   mHeight = imageTicket->GetHeight();
218   mLoadingFinishedV2.Emit( Dali::Image( this ) );
219 }
220
221 void Image::ResourceUploaded(const ResourceTicket& ticket)
222 {
223   mUploadedV2.Emit( Dali::Image( this ) );
224 }
225
226 void Image::ResourceSavingSucceeded( const ResourceTicket& ticket )
227 {
228   // do nothing
229 }
230
231 void Image::ResourceSavingFailed( const ResourceTicket& ticket )
232 {
233   // do nothing
234 }
235
236 unsigned int Image::GetWidth() const
237 {
238   if( mTicket )
239   {
240     const ImageAttributes& attr = mImageFactory.GetActualAttributes( mTicket->GetId() );
241     return attr.GetWidth();
242   }
243   else if( mRequest )
244   {
245     const ImageAttributes& attr = mImageFactory.GetRequestAttributes( mRequest.Get() );
246     return attr.GetWidth();
247   }
248   else
249   {
250     return mWidth;
251   }
252 }
253
254 unsigned int Image::GetHeight() const
255 {
256   if( mTicket )
257   {
258     const ImageAttributes& attr = mImageFactory.GetActualAttributes( mTicket->GetId() );
259     return attr.GetHeight();
260   }
261   else if( mRequest )
262   {
263     const ImageAttributes& attr = mImageFactory.GetRequestAttributes( mRequest.Get() );
264     return attr.GetHeight();
265   }
266   else
267   {
268     return mHeight;
269   }
270 }
271
272 void Image::Connect()
273 {
274   ++mConnectionCount;
275
276   if( mConnectionCount == 1 )
277   {
278     // ticket was thrown away when related actors went offstage or image loading on demand
279     if( !mTicket )
280     {
281       ResourceTicketPtr newTicket = mImageFactory.Load( mRequest.Get() );
282       SetTicket( newTicket.Get() );
283     }
284   }
285 }
286
287 void Image::Disconnect()
288 {
289   if( !mTicket )
290   {
291     return;
292   }
293
294   DALI_ASSERT_DEBUG( mConnectionCount > 0 );
295   --mConnectionCount;
296   if( mConnectionCount == 0 && mReleasePolicy == Dali::Image::Unused )
297   {
298     // release image memory when it's not visible anymore (decrease ref. count of texture)
299     SetTicket( NULL );
300   }
301 }
302
303 void Image::SetTicket( ResourceTicket* ticket )
304 {
305   if( ticket == mTicket.Get() )
306   {
307     return;
308   }
309
310   if( mTicket )
311   {
312     mTicket->RemoveObserver( *this );
313     mImageFactory.ReleaseTicket( mTicket.Get() );
314   }
315
316   if( ticket )
317   {
318     mTicket.Reset( ticket );
319     mTicket->AddObserver( *this );
320   }
321   else
322   {
323     mTicket.Reset();
324   }
325 }
326
327 } // namespace Internal
328
329 } // namespace Dali