(ImageLoader) Added synchronous method to get closest image size
[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, const Dali::ImageAttributes& attributes, LoadPolicy loadPol, ReleasePolicy releasePol )
55 {
56   Image* image = new Image( loadPol, releasePol );
57
58   if( ! filename.empty() )
59   {
60     Vector2 closestSize;
61
62     Internal::ThreadLocalStorage::Get().GetPlatformAbstraction().GetClosestImageSize( filename, attributes, closestSize );
63     image->mWidth = closestSize.width;
64     image->mHeight = closestSize.height;
65   }
66
67   image->mRequest = image->mImageFactory.RegisterRequest( filename, &attributes );
68
69   if( Dali::Image::Immediate == loadPol )
70   {
71     // Trigger loading of the image on a seperate resource thread as soon as it
72     // can be scheduled:
73     image->mTicket = image->mImageFactory.Load( image->mRequest.Get() );
74     image->mTicket->AddObserver( *image );
75   }
76   // else lazily load image data later, only when it is needed to draw something:
77
78   DALI_LOG_SET_OBJECT_STRING( image, filename );
79
80   return image;
81 }
82
83 Image* Image::New( NativeImage& nativeImg, LoadPolicy loadPol, ReleasePolicy releasePol )
84 {
85   Image* image = new Image;
86   ResourceClient &resourceClient = ThreadLocalStorage::Get().GetResourceClient();
87
88
89   image->mWidth  = nativeImg.GetWidth();
90   image->mHeight = nativeImg.GetHeight();
91
92   const ResourceTicketPtr& ticket = resourceClient.AddNativeImage( nativeImg );
93   DALI_ASSERT_DEBUG( dynamic_cast<ImageTicket*>( ticket.Get() ) && "Resource ticket not ImageTicket subclass for image resource.\n" );
94   image->mTicket = static_cast<ImageTicket*>(ticket.Get());
95   image->mTicket->AddObserver( *image );
96
97   return image;
98 }
99
100 Image::~Image()
101 {
102   if( mTicket )
103   {
104     mTicket->RemoveObserver( *this );
105     if( Stage::IsInstalled() )
106     {
107       mImageFactory.ReleaseTicket( mTicket.Get() );
108     }
109   }
110 }
111
112 bool Image::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
113 {
114   bool connected( true );
115   DALI_ASSERT_DEBUG( dynamic_cast<Image*>( object ) && "Resource ticket not ImageTicket subclass for image resource.\n" );
116   Image* image = static_cast<Image*>(object);
117
118   if( Dali::Image::SIGNAL_IMAGE_LOADING_FINISHED == signalName )
119   {
120     image->LoadingFinishedSignal().Connect( tracker, functor );
121   }
122   else if(Dali::Image::SIGNAL_IMAGE_UPLOADED == signalName)
123   {
124     image->UploadedSignal().Connect( tracker, functor );
125   }
126   else
127   {
128     // signalName does not match any signal
129     connected = false;
130   }
131
132   return connected;
133 }
134
135 ResourceId Image::GetResourceId() const
136 {
137   ResourceId ret = mTicket ? mTicket->GetId() : 0;
138
139   return ret;
140 }
141
142 const Dali::ImageAttributes& Image::GetAttributes() const
143 {
144   if( mTicket )
145   {
146     return mImageFactory.GetActualAttributes( mTicket->GetId() );
147   }
148   else
149   {
150     return mImageFactory.GetRequestAttributes( mRequest.Get() );
151   }
152 }
153
154 const std::string& Image::GetFilename() const
155 {
156   return mImageFactory.GetRequestPath( mRequest.Get() );
157 }
158
159 void Image::Reload()
160 {
161   if ( mRequest )
162   {
163     ResourceTicketPtr ticket = mImageFactory.Reload( mRequest.Get() );
164     SetTicket( ticket.Get() );
165   }
166 }
167
168 void Image::ResourceLoadingFailed(const ResourceTicket& ticket)
169 {
170   mLoadingFinishedV2.Emit( Dali::Image( this ) );
171 }
172
173 void Image::ResourceLoadingSucceeded(const ResourceTicket& ticket)
174 {
175   // Update size with actual loaded size
176   const ImageTicket* imageTicket = static_cast<const ImageTicket*>(&ticket);
177   mWidth = imageTicket->GetWidth();
178   mHeight = imageTicket->GetHeight();
179   mLoadingFinishedV2.Emit( Dali::Image( this ) );
180 }
181
182 void Image::ResourceUploaded(const ResourceTicket& ticket)
183 {
184   mUploadedV2.Emit( Dali::Image( this ) );
185 }
186
187 void Image::ResourceSavingSucceeded( const ResourceTicket& ticket )
188 {
189   // do nothing
190 }
191
192 void Image::ResourceSavingFailed( const ResourceTicket& ticket )
193 {
194   // do nothing
195 }
196
197 unsigned int Image::GetWidth() const
198 {
199   if( mTicket )
200   {
201     const ImageAttributes& attr = mImageFactory.GetActualAttributes( mTicket->GetId() );
202     return attr.GetWidth();
203   }
204   else if( mRequest )
205   {
206     const ImageAttributes& attr = mImageFactory.GetRequestAttributes( mRequest.Get() );
207     return attr.GetWidth();
208   }
209   else
210   {
211     return mWidth;
212   }
213 }
214
215 unsigned int Image::GetHeight() const
216 {
217   if( mTicket )
218   {
219     const ImageAttributes& attr = mImageFactory.GetActualAttributes( mTicket->GetId() );
220     return attr.GetHeight();
221   }
222   else if( mRequest )
223   {
224     const ImageAttributes& attr = mImageFactory.GetRequestAttributes( mRequest.Get() );
225     return attr.GetHeight();
226   }
227   else
228   {
229     return mHeight;
230   }
231 }
232
233 void Image::Connect()
234 {
235   ++mConnectionCount;
236
237   if( mConnectionCount == 1 )
238   {
239     // ticket was thrown away when related actors went offstage or image loading on demand
240     if( !mTicket )
241     {
242       ResourceTicketPtr newTicket = mImageFactory.Load( mRequest.Get() );
243       SetTicket( newTicket.Get() );
244     }
245   }
246 }
247
248 void Image::Disconnect()
249 {
250   if( !mTicket )
251   {
252     return;
253   }
254
255   DALI_ASSERT_DEBUG( mConnectionCount > 0 );
256   --mConnectionCount;
257   if( mConnectionCount == 0 && mReleasePolicy == Dali::Image::Unused )
258   {
259     // release image memory when it's not visible anymore (decrease ref. count of texture)
260     SetTicket( NULL );
261   }
262 }
263
264 void Image::SetTicket( ResourceTicket* ticket )
265 {
266   if( ticket == mTicket.Get() )
267   {
268     return;
269   }
270
271   if( mTicket )
272   {
273     mTicket->RemoveObserver( *this );
274     mImageFactory.ReleaseTicket( mTicket.Get() );
275   }
276
277   if( ticket )
278   {
279     mTicket.Reset( ticket );
280     mTicket->AddObserver( *this );
281   }
282   else
283   {
284     mTicket.Reset();
285   }
286 }
287
288 } // namespace Internal
289
290 } // namespace Dali