[dali_1.2.6] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / internal / event / images / resource-image-impl.cpp
1 /*
2  * Copyright (c) 2016 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 = "imageLoadingFinished";
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()
61 : Image(),
62   mImageFactory( ThreadLocalStorage::Get().GetImageFactory() )
63 {
64 }
65
66 ResourceImagePtr ResourceImage::New()
67 {
68   ResourceImagePtr image = new ResourceImage;
69   image->Initialize();
70   return image;
71 }
72
73 ResourceImagePtr ResourceImage::New( const std::string& url, const ImageAttributes& attributes )
74 {
75   ResourceImagePtr image;
76   if( NinePatchImage::IsNinePatchUrl( url ) )
77   {
78     image = NinePatchImage::New( url );
79   }
80   else
81   {
82     image = new ResourceImage();
83     image->Initialize();
84
85     // consider the requested size as natural size, 0 means we don't (yet) know it
86     image->mWidth = attributes.GetWidth();
87     image->mHeight = attributes.GetHeight();
88     image->mRequest = image->mImageFactory.RegisterRequest( url, &attributes );
89     image->mTicket = image->mImageFactory.Load( *image->mRequest.Get() );
90     image->mTicket->AddObserver( *image );
91   }
92   DALI_LOG_SET_OBJECT_STRING( image, url );
93
94   return image;
95 }
96
97 ResourceImage::~ResourceImage()
98 {
99   if( mTicket )
100   {
101     mTicket->RemoveObserver( *this );
102     if( Stage::IsInstalled() )
103     {
104       mImageFactory.ReleaseTicket( mTicket.Get() );
105     }
106     mTicket.Reset();
107   }
108 }
109
110 bool ResourceImage::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
111 {
112   bool connected( true );
113   DALI_ASSERT_DEBUG( dynamic_cast<ResourceImage*>( object ) && "Resource ticket not ImageTicket subclass for image resource.\n" );
114   ResourceImage* image = static_cast<ResourceImage*>(object);
115
116   if( 0 == strcmp( signalName.c_str(), SIGNAL_IMAGE_LOADING_FINISHED ) )
117   {
118     image->LoadingFinishedSignal().Connect( tracker, functor );
119   }
120   else
121   {
122     // signalName does not match any signal
123     connected = false;
124   }
125
126   return connected;
127 }
128
129 const ImageAttributes& ResourceImage::GetAttributes() const
130 {
131   if( mTicket )
132   {
133     return mImageFactory.GetActualAttributes( mTicket );
134   }
135   else
136   {
137     return mImageFactory.GetRequestAttributes( mRequest );
138   }
139 }
140
141 const std::string& ResourceImage::GetUrl() const
142 {
143   return mImageFactory.GetRequestPath( mRequest );
144 }
145
146 void ResourceImage::Reload()
147 {
148   if ( mRequest )
149   {
150     ResourceTicketPtr ticket = mImageFactory.Reload( *mRequest.Get() );
151     SetTicket( ticket.Get() );
152   }
153 }
154
155 unsigned int ResourceImage::GetWidth() const
156 {
157   // if width is 0, it means we've not yet loaded the image
158   if( 0u == mWidth )
159   {
160     Size size;
161     mImageFactory.GetImageSize( mRequest, mTicket, size );
162     mWidth = size.width;
163     if( 0 == mHeight )
164     {
165       mHeight = size.height;
166     }
167   }
168   return mWidth;
169 }
170
171 unsigned int ResourceImage::GetHeight() const
172 {
173   if( 0u == mHeight )
174   {
175     Size size;
176     mImageFactory.GetImageSize( mRequest, mTicket, size );
177     mHeight = size.height;
178     if( 0 == mWidth )
179     {
180       mWidth = size.width;
181     }
182   }
183   return mHeight;
184 }
185
186 Vector2 ResourceImage::GetNaturalSize() const
187 {
188   Vector2 naturalSize(mWidth, mHeight);
189   if( 0u == mWidth || 0u == mHeight )
190   {
191     mImageFactory.GetImageSize( mRequest, mTicket, naturalSize );
192     mWidth = naturalSize.width;
193     mHeight = naturalSize.height;
194   }
195   return naturalSize;
196 }
197
198 void ResourceImage::ResourceLoadingFailed(const ResourceTicket& ticket)
199 {
200   mLoadingFinished.Emit( Dali::ResourceImage( this ) );
201 }
202
203 void ResourceImage::ResourceLoadingSucceeded(const ResourceTicket& ticket)
204 {
205   mLoadingFinished.Emit( Dali::ResourceImage( this ) );
206 }
207
208 void ResourceImage::Connect()
209 {
210   ++mConnectionCount;
211
212   if( mConnectionCount == 1 )
213   {
214     // ticket was thrown away when related actors went offstage or image loading on demand
215     if( !mTicket )
216     {
217       DALI_ASSERT_DEBUG( mRequest.Get() );
218       ResourceTicketPtr newTicket = mImageFactory.Load( *mRequest.Get() );
219       SetTicket( newTicket.Get() );
220     }
221   }
222 }
223
224 void ResourceImage::Disconnect()
225 {
226   if( !mTicket )
227   {
228     return;
229   }
230
231   DALI_ASSERT_DEBUG( mConnectionCount > 0 );
232   --mConnectionCount;
233   if( mConnectionCount == 0 )
234   {
235     // release image memory when it's not visible anymore (decrease ref. count of texture)
236     SetTicket( NULL );
237   }
238 }
239
240 void ResourceImage::SetTicket( ResourceTicket* ticket )
241 {
242   if( ticket == mTicket.Get() )
243   {
244     return;
245   }
246
247   if( mTicket )
248   {
249     mTicket->RemoveObserver( *this );
250     mImageFactory.ReleaseTicket( mTicket.Get() );
251   }
252
253   if( ticket )
254   {
255     mTicket.Reset( ticket );
256     mTicket->AddObserver( *this );
257   }
258   else
259   {
260     mTicket.Reset();
261   }
262 }
263
264 } // namespace Internal
265
266 } // namespace Dali