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