Added object sizes to platform abstraction in profiling section
[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 #include <dali/public-api/object/type-registry.h>
23
24 #include <dali/integration-api/platform-abstraction.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/internal/event/resources/resource-ticket.h>
27 #include <dali/internal/event/common/thread-local-storage.h>
28 #include <dali/internal/event/resources/resource-client.h>
29 #include <dali/internal/event/images/image-factory.h>
30 #include <dali/internal/event/images/nine-patch-image-impl.h>
31 #include <dali/internal/event/common/stage-impl.h>
32
33 using namespace Dali::Integration;
34
35 namespace Dali
36 {
37
38 namespace Internal
39 {
40
41 namespace
42 {
43
44 BaseHandle CreateImage()
45 {
46   ImagePtr image = Image::New();
47   return Dali::Image(image.Get());
48 }
49
50 TypeRegistration mType( typeid(Dali::Image), typeid(Dali::BaseHandle), CreateImage );
51
52 Dali::SignalConnectorType signalConnector1(mType, Dali::Image::SIGNAL_IMAGE_LOADING_FINISHED,    &Image::DoConnectSignal);
53 Dali::SignalConnectorType signalConnector2(mType, Dali::Image::SIGNAL_IMAGE_UPLOADED,            &Image::DoConnectSignal);
54 }
55
56 Image::Image( LoadPolicy loadPol, ReleasePolicy releasePol )
57 : mWidth(0),
58   mHeight(0),
59   mLoadPolicy(loadPol),
60   mReleasePolicy(releasePol),
61   mConnectionCount(0),
62   mImageFactory(ThreadLocalStorage::Get().GetImageFactory())
63 {
64 }
65
66 ImagePtr Image::New()
67 {
68   ImagePtr image = new Image;
69   image->Initialize();
70   return image;
71 }
72
73 ImagePtr Image::New( const std::string& filename, const Dali::ImageAttributes& attributes, LoadPolicy loadPol, ReleasePolicy releasePol )
74 {
75   if( IsNinePatchFileName(filename) )
76   {
77     NinePatchImagePtr image = NinePatchImage::New( filename, attributes, loadPol, releasePol );
78     return image;
79   }
80   else
81   {
82     ImagePtr image = new Image( loadPol, releasePol );
83     image->Initialize();
84
85     if( ! filename.empty() )
86     {
87       Vector2 closestSize;
88
89       Internal::ThreadLocalStorage::Get().GetPlatformAbstraction().GetClosestImageSize( filename, attributes, closestSize );
90       image->mWidth = closestSize.width;
91       image->mHeight = closestSize.height;
92     }
93
94     image->mRequest = image->mImageFactory.RegisterRequest( filename, &attributes );
95
96     if( Dali::Image::Immediate == loadPol )
97     {
98       // Trigger loading of the image on a seperate resource thread as soon as it
99       // can be scheduled:
100       image->mTicket = image->mImageFactory.Load( image->mRequest.Get() );
101       image->mTicket->AddObserver( *image );
102     }
103
104     // else lazily load image data later, only when it is needed to draw something:
105
106     DALI_LOG_SET_OBJECT_STRING( image, filename );
107
108     return image;
109   }
110 }
111
112 ImagePtr Image::New( NativeImage& nativeImg, LoadPolicy loadPol, ReleasePolicy releasePol )
113 {
114   ImagePtr image = new Image;
115   image->Initialize();
116
117   ResourceClient &resourceClient = ThreadLocalStorage::Get().GetResourceClient();
118
119   image->mWidth  = nativeImg.GetWidth();
120   image->mHeight = nativeImg.GetHeight();
121
122   const ResourceTicketPtr& ticket = resourceClient.AddNativeImage( nativeImg );
123   DALI_ASSERT_DEBUG( dynamic_cast<ImageTicket*>( ticket.Get() ) && "Resource ticket not ImageTicket subclass for image resource.\n" );
124   image->mTicket = static_cast<ImageTicket*>(ticket.Get());
125   image->mTicket->AddObserver( *image );
126
127   return image;
128 }
129
130 Image::~Image()
131 {
132   if( mTicket )
133   {
134     mTicket->RemoveObserver( *this );
135     if( Stage::IsInstalled() )
136     {
137       mImageFactory.ReleaseTicket( mTicket.Get() );
138     }
139   }
140
141   if( Stage::IsInstalled() )
142   {
143     UnregisterObject();
144   }
145 }
146
147 bool Image::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
148 {
149   bool connected( true );
150   DALI_ASSERT_DEBUG( dynamic_cast<Image*>( object ) && "Resource ticket not ImageTicket subclass for image resource.\n" );
151   Image* image = static_cast<Image*>(object);
152
153   if( Dali::Image::SIGNAL_IMAGE_LOADING_FINISHED == signalName )
154   {
155     image->LoadingFinishedSignal().Connect( tracker, functor );
156   }
157   else if(Dali::Image::SIGNAL_IMAGE_UPLOADED == signalName)
158   {
159     image->UploadedSignal().Connect( tracker, functor );
160   }
161   else
162   {
163     // signalName does not match any signal
164     connected = false;
165   }
166
167   return connected;
168 }
169
170 ResourceId Image::GetResourceId() const
171 {
172   ResourceId ret = mTicket ? mTicket->GetId() : 0;
173
174   return ret;
175 }
176
177 const Dali::ImageAttributes& Image::GetAttributes() const
178 {
179   if( mTicket )
180   {
181     return mImageFactory.GetActualAttributes( mTicket->GetId() );
182   }
183   else
184   {
185     return mImageFactory.GetRequestAttributes( mRequest.Get() );
186   }
187 }
188
189 const std::string& Image::GetFilename() const
190 {
191   return mImageFactory.GetRequestPath( mRequest.Get() );
192 }
193
194 void Image::Reload()
195 {
196   if ( mRequest )
197   {
198     ResourceTicketPtr ticket = mImageFactory.Reload( mRequest.Get() );
199     SetTicket( ticket.Get() );
200   }
201 }
202
203 void Image::ResourceLoadingFailed(const ResourceTicket& ticket)
204 {
205   mLoadingFinishedV2.Emit( Dali::Image( this ) );
206 }
207
208 void Image::ResourceLoadingSucceeded(const ResourceTicket& ticket)
209 {
210   // Update size with actual loaded size
211   const ImageTicket* imageTicket = static_cast<const ImageTicket*>(&ticket);
212   mWidth = imageTicket->GetWidth();
213   mHeight = imageTicket->GetHeight();
214   mLoadingFinishedV2.Emit( Dali::Image( this ) );
215 }
216
217 void Image::ResourceUploaded(const ResourceTicket& ticket)
218 {
219   mUploadedV2.Emit( Dali::Image( this ) );
220 }
221
222 void Image::ResourceSavingSucceeded( const ResourceTicket& ticket )
223 {
224   // do nothing
225 }
226
227 void Image::ResourceSavingFailed( const ResourceTicket& ticket )
228 {
229   // do nothing
230 }
231
232 unsigned int Image::GetWidth() const
233 {
234   // Width has already been calculated - just return that
235   return mWidth;
236 }
237
238 unsigned int Image::GetHeight() const
239 {
240   // Height has already been calculated - just return that
241   return mHeight;
242 }
243
244 Vector2 Image::GetNaturalSize() const
245 {
246   return Vector2( mWidth, mHeight );
247 }
248
249 void Image::Connect()
250 {
251   ++mConnectionCount;
252
253   if( mConnectionCount == 1 )
254   {
255     // ticket was thrown away when related actors went offstage or image loading on demand
256     if( !mTicket )
257     {
258       ResourceTicketPtr newTicket = mImageFactory.Load( mRequest.Get() );
259       SetTicket( newTicket.Get() );
260     }
261   }
262 }
263
264 void Image::Disconnect()
265 {
266   if( !mTicket )
267   {
268     return;
269   }
270
271   DALI_ASSERT_DEBUG( mConnectionCount > 0 );
272   --mConnectionCount;
273   if( mConnectionCount == 0 && mReleasePolicy == Dali::Image::Unused )
274   {
275     // release image memory when it's not visible anymore (decrease ref. count of texture)
276     SetTicket( NULL );
277   }
278 }
279
280 void Image::Initialize()
281 {
282   RegisterObject();
283 }
284
285 void Image::SetTicket( ResourceTicket* ticket )
286 {
287   if( ticket == mTicket.Get() )
288   {
289     return;
290   }
291
292   if( mTicket )
293   {
294     mTicket->RemoveObserver( *this );
295     mImageFactory.ReleaseTicket( mTicket.Get() );
296   }
297
298   if( ticket )
299   {
300     mTicket.Reset( ticket );
301     mTicket->AddObserver( *this );
302   }
303   else
304   {
305     mTicket.Reset();
306   }
307 }
308
309 bool Image::IsNinePatchFileName( std::string filename )
310 {
311   bool match = false;
312
313   std::string::const_reverse_iterator iter = filename.rbegin();
314   enum { SUFFIX, HASH, HASH_DOT, DONE } state = SUFFIX;
315   while(iter < filename.rend())
316   {
317     switch(state)
318     {
319       case SUFFIX:
320       {
321         if(*iter == '.')
322         {
323           state = HASH;
324         }
325         else if(!isalnum(*iter))
326         {
327           state = DONE;
328         }
329       }
330       break;
331       case HASH:
332       {
333         if( *iter == '#' || *iter == '9' )
334         {
335           state = HASH_DOT;
336         }
337         else
338         {
339           state = DONE;
340         }
341       }
342       break;
343       case HASH_DOT:
344       {
345         if(*iter == '.')
346         {
347           match = true;
348         }
349         state = DONE; // Stop testing characters
350       }
351       break;
352       case DONE:
353       {
354       }
355       break;
356     }
357
358     // Satisfy prevnet
359     if( state == DONE )
360     {
361       break;
362     }
363
364     iter++;
365   }
366   return match;
367 }
368
369
370 } // namespace Internal
371
372 } // namespace Dali