Merge "Changed NinePatchImage to support parsing of n-patches." into devel/master
[platform/core/uifw/dali-core.git] / dali / internal / event / images / resource-image-impl.cpp
1 /*
2  * Copyright (c) 2015 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 <dali/internal/event/images/resource-image-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <cstring> // for strcmp
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/common/dali-common.h>
26 #include <dali/public-api/object/type-registry.h>
27 #include <dali/integration-api/debug.h>
28 #include <dali/internal/event/common/thread-local-storage.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 // Signals
45
46 const char* const SIGNAL_IMAGE_LOADING_FINISHED = "image-loading-finished";
47
48 BaseHandle CreateImage()
49 {
50   ImagePtr image = ResourceImage::New();
51   return Dali::Image(image.Get());
52 }
53
54 TypeRegistration mType( typeid( Dali::ResourceImage ), typeid( Dali::Image ), CreateImage );
55
56 Dali::SignalConnectorType signalConnector1( mType, SIGNAL_IMAGE_LOADING_FINISHED, &ResourceImage::DoConnectSignal );
57
58 }
59
60 ResourceImage::ResourceImage( LoadPolicy loadPol, ReleasePolicy releasePol )
61 : Image( releasePol ),
62   mImageFactory( ThreadLocalStorage::Get().GetImageFactory() ),
63   mLoadPolicy(loadPol)
64 {
65 }
66
67 ResourceImagePtr ResourceImage::New()
68 {
69   ResourceImagePtr image = new ResourceImage;
70   image->Initialize();
71   return image;
72 }
73
74 ResourceImagePtr ResourceImage::New( const std::string& url, const ImageAttributes& attributes, LoadPolicy loadPol, ReleasePolicy releasePol )
75 {
76   ResourceImagePtr image;
77   if( NinePatchImage::IsNinePatchUrl( url ) )
78   {
79     image = NinePatchImage::New( url, attributes, releasePol );
80   }
81   else
82   {
83     image = new ResourceImage( loadPol, releasePol );
84     image->Initialize();
85
86     // consider the requested size as natural size, 0 means we don't (yet) know it
87     image->mWidth = attributes.GetWidth();
88     image->mHeight = attributes.GetHeight();
89     image->mRequest = image->mImageFactory.RegisterRequest( url, &attributes );
90
91     if( Dali::ResourceImage::IMMEDIATE == loadPol )
92     {
93       // Trigger loading of the image on a as soon as it can be done
94       image->mTicket = image->mImageFactory.Load( *image->mRequest.Get() );
95       image->mTicket->AddObserver( *image );
96     }
97   }
98   DALI_LOG_SET_OBJECT_STRING( image, url );
99
100   return image;
101 }
102
103 ResourceImage::~ResourceImage()
104 {
105   if( mTicket )
106   {
107     mTicket->RemoveObserver( *this );
108     if( Stage::IsInstalled() )
109     {
110       mImageFactory.ReleaseTicket( mTicket.Get() );
111     }
112     mTicket.Reset();
113   }
114 }
115
116 bool ResourceImage::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
117 {
118   bool connected( true );
119   DALI_ASSERT_DEBUG( dynamic_cast<ResourceImage*>( object ) && "Resource ticket not ImageTicket subclass for image resource.\n" );
120   ResourceImage* image = static_cast<ResourceImage*>(object);
121
122   if( 0 == strcmp( signalName.c_str(), SIGNAL_IMAGE_LOADING_FINISHED ) )
123   {
124     image->LoadingFinishedSignal().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 const ImageAttributes& ResourceImage::GetAttributes() const
136 {
137   if( mTicket )
138   {
139     return mImageFactory.GetActualAttributes( mTicket );
140   }
141   else
142   {
143     return mImageFactory.GetRequestAttributes( mRequest );
144   }
145 }
146
147 const std::string& ResourceImage::GetUrl() const
148 {
149   return mImageFactory.GetRequestPath( mRequest );
150 }
151
152 void ResourceImage::Reload()
153 {
154   if ( mRequest )
155   {
156     ResourceTicketPtr ticket = mImageFactory.Reload( *mRequest.Get() );
157     SetTicket( ticket.Get() );
158   }
159 }
160
161 unsigned int ResourceImage::GetWidth() const
162 {
163   // if width is 0, it means we've not yet loaded the image
164   if( 0u == mWidth )
165   {
166     Size size;
167     mImageFactory.GetImageSize( mRequest, mTicket, size );
168     mWidth = size.width;
169     if( 0 == mHeight )
170     {
171       mHeight = size.height;
172     }
173   }
174   return mWidth;
175 }
176
177 unsigned int ResourceImage::GetHeight() const
178 {
179   if( 0u == mHeight )
180   {
181     Size size;
182     mImageFactory.GetImageSize( mRequest, mTicket, size );
183     mHeight = size.height;
184     if( 0 == mWidth )
185     {
186       mWidth = size.width;
187     }
188   }
189   return mHeight;
190 }
191
192 Vector2 ResourceImage::GetNaturalSize() const
193 {
194   Vector2 naturalSize(mWidth, mHeight);
195   if( 0u == mWidth || 0u == mHeight )
196   {
197     mImageFactory.GetImageSize( mRequest, mTicket, naturalSize );
198     mWidth = naturalSize.width;
199     mHeight = naturalSize.height;
200   }
201   return naturalSize;
202 }
203
204 void ResourceImage::ResourceLoadingFailed(const ResourceTicket& ticket)
205 {
206   mLoadingFinished.Emit( Dali::ResourceImage( this ) );
207 }
208
209 void ResourceImage::ResourceLoadingSucceeded(const ResourceTicket& ticket)
210 {
211   mLoadingFinished.Emit( Dali::ResourceImage( this ) );
212 }
213
214 void ResourceImage::Connect()
215 {
216   ++mConnectionCount;
217
218   if( mConnectionCount == 1 )
219   {
220     // ticket was thrown away when related actors went offstage or image loading on demand
221     if( !mTicket )
222     {
223       DALI_ASSERT_DEBUG( mRequest.Get() );
224       ResourceTicketPtr newTicket = mImageFactory.Load( *mRequest.Get() );
225       SetTicket( newTicket.Get() );
226     }
227   }
228 }
229
230 void ResourceImage::Disconnect()
231 {
232   if( !mTicket )
233   {
234     return;
235   }
236
237   DALI_ASSERT_DEBUG( mConnectionCount > 0 );
238   --mConnectionCount;
239   if( mConnectionCount == 0 && mReleasePolicy == Dali::ResourceImage::UNUSED )
240   {
241     // release image memory when it's not visible anymore (decrease ref. count of texture)
242     SetTicket( NULL );
243   }
244 }
245
246 void ResourceImage::SetTicket( ResourceTicket* ticket )
247 {
248   if( ticket == mTicket.Get() )
249   {
250     return;
251   }
252
253   if( mTicket )
254   {
255     mTicket->RemoveObserver( *this );
256     mImageFactory.ReleaseTicket( mTicket.Get() );
257   }
258
259   if( ticket )
260   {
261     mTicket.Reset( ticket );
262     mTicket->AddObserver( *this );
263   }
264   else
265   {
266     mTicket.Reset();
267   }
268 }
269
270 } // namespace Internal
271
272 } // namespace Dali