Removed some redundant texture features
[platform/core/uifw/dali-core.git] / dali / internal / event / resources / resource-client.cpp
1 /*
2  * Copyright (c) 2014 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 // INTERNAL INCLUDES
19 #include <dali/internal/event/resources/resource-client.h>
20 #include <dali/public-api/common/map-wrapper.h>
21
22 #include <dali/integration-api/resource-request.h>
23 #include <dali/integration-api/debug.h>
24
25 #include <dali/internal/event/common/stage-impl.h>
26 #include <dali/internal/event/images/image-impl.h>
27 #include <dali/internal/update/resources/resource-manager.h>
28 #include <dali/internal/update/manager/update-manager.h>
29
30
31 namespace Dali
32 {
33 namespace Internal
34 {
35 using namespace Dali::Integration;
36
37 typedef std::map<ResourceId, ResourceTicket*>        TicketContainer;
38 typedef TicketContainer::iterator                    TicketContainerIter;
39 typedef TicketContainer::size_type                   TicketContainerSize;
40 typedef std::pair<ResourceId, ResourceTicket*>       TicketPair;
41
42 typedef std::map<ResourceId, Bitmap*>                BitmapCache;
43 typedef BitmapCache::iterator                        BitmapCacheIter;
44
45 struct ResourceClient::Impl
46 {
47   Impl(ResourcePolicy::DataRetention dataRetentionPolicy)
48   : mNextId(0),
49     mDataRetentionPolicy( dataRetentionPolicy )
50   {
51   }
52
53   ResourceId       mNextId;
54   TicketContainer  mTickets;
55   BitmapCache      mBitmaps;
56   ResourcePolicy::DataRetention mDataRetentionPolicy;
57 };
58
59 ResourceClient::ResourceClient( ResourceManager& resourceManager,
60                                 SceneGraph::UpdateManager& updateManager,
61                                 ResourcePolicy::DataRetention dataRetentionPolicy)
62 : mResourceManager(resourceManager),
63   mUpdateManager(updateManager)
64 {
65   mImpl = new ResourceClient::Impl(dataRetentionPolicy);
66   mResourceManager.SetClient(*this);
67 }
68
69 ResourceClient::~ResourceClient()
70 {
71   // Guard to allow handle destruction after Core has been destroyed
72   if ( Stage::IsInstalled() )
73   {
74     for (TicketContainerIter iter = mImpl->mTickets.begin(); iter != mImpl->mTickets.end(); ++iter)
75     {
76       (*iter).second->StopLifetimeObservation();
77     }
78   }
79   delete mImpl;
80 }
81
82 ResourcePolicy::DataRetention ResourceClient::GetResourceDataRetentionPolicy()
83 {
84   return mImpl->mDataRetentionPolicy;
85 }
86
87 ResourceTicketPtr ResourceClient::RequestResource(
88   const ResourceType& type,
89   const std::string& path,
90   LoadResourcePriority priority )
91 {
92   ResourceTicketPtr newTicket;
93   ResourceTypePath typePath(type, path);
94   ResourceId newId = 0;
95
96   // Create the ticket first
97   // NOTE: pre-increment, otherwise we get 0 for first one.
98   newId = ++(mImpl->mNextId);
99
100   switch (type.id)
101   {
102     case ResourceBitmap:
103     {
104       const BitmapResourceType& bitmapResource = static_cast <const BitmapResourceType&> (type);
105       // image tickets will cache the requested parameters, which are updated on successful loading
106       ImageTicket* imageTicket = new ImageTicket(*this, newId, typePath);
107       imageTicket->mAttributes = bitmapResource.imageAttributes;
108       newTicket = imageTicket;
109       break;
110     }
111
112     case ResourceNativeImage:
113     {
114       const NativeImageResourceType& nativeResource = static_cast <const NativeImageResourceType&> (type);
115       // image tickets will cache the requested parameters, which are updated on successful loading
116       ImageTicket* imageTicket = new ImageTicket(*this, newId, typePath);
117       imageTicket->mAttributes = nativeResource.imageAttributes;
118       newTicket = imageTicket;
119       break;
120     }
121     case ResourceModel:       // FALLTHROUGH
122     case ResourceTargetImage:
123     case ResourceShader:
124     case ResourceMesh:
125     {
126       newTicket = new ResourceTicket(*this, newId, typePath);
127       break;
128     }
129   }
130
131   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
132
133   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResource(path:%s type.id:%d) newId:%u\n", path.c_str(), type.id, newId);
134
135   RequestLoadResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, typePath, priority );
136   return newTicket;
137 }
138
139 ResourceTicketPtr ResourceClient::DecodeResource(
140   const ResourceType& type,
141   RequestBufferPtr buffer,
142   LoadResourcePriority priority )
143 {
144   DALI_ASSERT_DEBUG( type.id == ResourceBitmap && "Only bitmap resources are currently decoded from memory buffers. It should be easy to expand to other resource types though. The public API function at the front and the resource thread at the back end are all that should need to be changed. The code in the middle should be agnostic to the the resource type it is conveying.\n" );
145   DALI_ASSERT_DEBUG( buffer.Get() && "Null resource buffer passed for decoding." );
146   ResourceTicketPtr newTicket;
147   if( buffer.Get() ) //< Check to avoid SEGV on a null pointer.
148   {
149     ResourceTypePath typePath( type, "" );
150     ResourceId newId = 0;
151
152     // Create the correct ticket type for the resource:
153     switch (type.id)
154     {
155       case ResourceBitmap:
156       {
157         // NOTE: pre-increment, otherwise we get 0 for first one.
158         newId = ++(mImpl->mNextId);
159         const BitmapResourceType& bitmapResource = static_cast <const BitmapResourceType&> ( type );
160         // Image tickets will cache the requested parameters, which are updated on successful loading
161         ImageTicket* imageTicket = new ImageTicket( *this, newId, typePath );
162         imageTicket->mAttributes = bitmapResource.imageAttributes;
163         newTicket = imageTicket;
164         break;
165       }
166
167       // FALLTHROUGH:
168       case ResourceNativeImage:
169       case ResourceModel:
170       case ResourceTargetImage:
171       case ResourceShader:
172       case ResourceMesh:
173       {
174         DALI_LOG_ERROR( "Unsupported resource type passed for decoding from a memory buffer." );
175       }
176     }
177
178     if( newTicket )
179     {
180       mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
181       DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: DecodeResource( type.id:%d ) newId:%u\n", type.id, newId);
182
183       RequestDecodeResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, typePath, buffer, priority );
184     }
185   }
186   return newTicket;
187 }
188
189 ResourceTicketPtr ResourceClient::LoadShader( ShaderResourceType& type,
190                                               const std::string& path )
191 {
192   ResourceTicketPtr newTicket;
193
194   const ResourceId newId = ++(mImpl->mNextId);
195
196   ResourceTypePath typePath(type, path);
197   newTicket = new ResourceTicket(*this, newId, typePath);
198
199   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
200
201   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: LoadShader(path:%s) newId:%u\n", path.c_str(), newId);
202
203   RequestLoadShaderMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, typePath );
204   return newTicket;
205 }
206
207 bool ResourceClient::ReloadResource( ResourceId id, bool resetFinishedStatus, LoadResourcePriority priority )
208 {
209   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ReloadResource(Id: %u)\n", id);
210
211   bool resourceExists = false;
212   TicketContainerIter ticketIter;
213   ticketIter = mImpl->mTickets.find(id);
214
215   if(ticketIter != mImpl->mTickets.end())
216   {
217     resourceExists = true;
218     // The ticket is already being observed
219     ResourceTicket* ticket = ticketIter->second;
220     DALI_ASSERT_DEBUG(ticket && "Null ticket for tracked resource request." );
221     const ResourceTypePath * const typePathPtr = &ticket->GetTypePath();
222     DALI_ASSERT_DEBUG( typePathPtr );
223     RequestReloadResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, id, *typePathPtr, priority, resetFinishedStatus );
224   }
225   else
226   {
227     DALI_LOG_ERROR ("Resource %d does not exist\n", id);
228   }
229   return resourceExists;
230 }
231
232 void ResourceClient::SaveResource( ResourceTicketPtr ticket, const std::string& url )
233 {
234   DALI_ASSERT_DEBUG( ticket );
235
236   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: SaveResource(Id: %u, path:%s)\n", ticket->GetId(), url.c_str());
237
238   const ResourceTypePath * const typePathPtr = &ticket->GetTypePath();
239   if( typePathPtr )
240   {
241     if( 0 != url.length() )
242     {
243       ResourceTypePath typePath( *(typePathPtr->type), url );
244       RequestSaveResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), typePath );
245     }
246     else
247     {
248       ResourceTypePath typePath( *typePathPtr );
249       RequestSaveResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), typePath );
250     }
251   }
252 }
253
254 ResourceTicketPtr ResourceClient::RequestResourceTicket( ResourceId id )
255 {
256   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResourceTicket(Id: %u)\n", id);
257
258   ResourceTicketPtr ticket;
259
260   TicketContainerIter ticketIter = mImpl->mTickets.find( id );
261
262   if ( mImpl->mTickets.end() != ticketIter )
263   {
264     ticket = ticketIter->second;
265   }
266
267   return ticket;
268 }
269
270 ImageTicketPtr ResourceClient::AllocateBitmapImage( unsigned int width,
271                                                     unsigned int height,
272                                                     unsigned int bufferWidth,
273                                                     unsigned int bufferHeight,
274                                                     Pixel::Format pixelformat )
275 {
276   /* buffer is available via public-api, therefore not discardable */
277   Bitmap* const bitmap = Bitmap::New( Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::RETAIN );
278   Bitmap::PackedPixelsProfile* const packedBitmap = bitmap->GetPackedPixelsProfile();
279   DALI_ASSERT_DEBUG(packedBitmap);
280
281   packedBitmap->ReserveBuffer(pixelformat, width, height, bufferWidth, bufferHeight);
282   DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
283   DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
284
285   ImageTicketPtr ticket = AddBitmapImage(bitmap);
286
287   DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
288   DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
289   return ticket;
290 }
291
292 ImageTicketPtr ResourceClient::AddBitmapImage(Bitmap* bitmap)
293 {
294   DALI_ASSERT_DEBUG( bitmap != NULL );
295
296   ImageTicketPtr newTicket;
297
298   const ResourceId newId = ++(mImpl->mNextId);
299
300   Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(bitmap->GetImageWidth(), bitmap->GetImageHeight(), bitmap->GetPixelFormat());
301   BitmapResourceType bitmapResourceType(imageAttributes); // construct first as no copy ctor (needed to bind ref to object)
302   ResourceTypePath typePath(bitmapResourceType, "");
303   newTicket = new ImageTicket(*this, newId, typePath);
304   newTicket->mAttributes = imageAttributes;
305   newTicket->LoadingSucceeded();
306
307   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
308
309   // Store bitmap for immediate access.
310   mImpl->mBitmaps[newId] = bitmap;
311
312   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddBitmapImage() New id = %u\n", newId);
313   RequestAddBitmapImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, bitmap );
314
315   return newTicket;
316 }
317
318 ResourceTicketPtr ResourceClient::AddNativeImage ( NativeImage& resourceData )
319 {
320   ImageTicketPtr newTicket;
321
322   const ResourceId newId = ++(mImpl->mNextId);
323   NativeImageResourceType nativeImageResourceType; // construct first as no copy ctor (needed to bind ref to object)
324   ResourceTypePath typePath(nativeImageResourceType, "");
325   newTicket = new ImageTicket(*this, newId, typePath);
326   newTicket->mAttributes = ImageAttributes::New(resourceData.GetWidth(),
327                                                 resourceData.GetHeight(),
328                                                 resourceData.GetPixelFormat());
329   newTicket->LoadingSucceeded();
330
331   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
332
333   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddNativeImage() New id = %u\n", newId);
334
335   RequestAddNativeImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, &resourceData );
336
337   return newTicket;
338 }
339
340 ImageTicketPtr ResourceClient::AddFrameBufferImage ( unsigned int width, unsigned int height, Pixel::Format pixelFormat )
341 {
342   ImageTicketPtr newTicket;
343
344   const ResourceId newId = ++(mImpl->mNextId);
345
346   Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(width, height, pixelFormat );
347   RenderTargetResourceType renderTargetResourceType(imageAttributes) ; // construct first as no copy ctor (needed to bind ref to object)
348   ResourceTypePath typePath(renderTargetResourceType, "");
349   newTicket = new ImageTicket(*this, newId, typePath);
350   newTicket->mAttributes = imageAttributes;
351   newTicket->LoadingSucceeded();
352
353   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
354
355   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
356   RequestAddFrameBufferImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, width, height, pixelFormat );
357
358   return newTicket;
359 }
360
361 ImageTicketPtr ResourceClient::AddFrameBufferImage ( NativeImage& nativeImage )
362 {
363   ImageTicketPtr newTicket;
364
365   const ResourceId newId = ++(mImpl->mNextId);
366
367   Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(nativeImage.GetWidth(), nativeImage.GetHeight(), nativeImage.GetPixelFormat() );
368   RenderTargetResourceType renderTargetResourceType(imageAttributes); // construct first as no copy ctor (needed to bind ref to object)
369   ResourceTypePath typePath(renderTargetResourceType, "");
370   newTicket = new ImageTicket(*this, newId, typePath);
371   newTicket->mAttributes = imageAttributes;
372   newTicket->LoadingSucceeded();
373
374   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
375
376   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
377   RequestAddFrameBufferImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, &nativeImage );
378
379   return newTicket;
380 }
381
382
383 ResourceTicketPtr ResourceClient::AllocateTexture( unsigned int width,
384                                                    unsigned int height,
385                                                    Pixel::Format pixelformat )
386 {
387   ImageTicketPtr newTicket;
388   const ResourceId newId = ++(mImpl->mNextId);
389
390   Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New( width, height, pixelformat);
391   BitmapResourceType bitmapResourceType(imageAttributes); // construct first as no copy ctor (needed to bind ref to object)
392   ResourceTypePath typePath(bitmapResourceType, "");
393   newTicket = new ImageTicket(*this, newId, typePath);
394
395   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
396   newTicket->mAttributes = imageAttributes;
397   newTicket->LoadingSucceeded();
398
399   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateTexture() New id = %u\n", newId);
400
401   RequestAllocateTextureMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, width, height, pixelformat );
402
403   return newTicket;
404 }
405
406 ResourceTicketPtr ResourceClient::AllocateMesh( OwnerPointer<MeshData>& meshData )
407 {
408   ResourceTicketPtr newTicket;
409   const ResourceId newId = ++(mImpl->mNextId);
410   MeshResourceType meshResourceType; // construct first as no copy ctor (needed to bind ref to object)
411   ResourceTypePath typePath(meshResourceType, "");
412   newTicket = new ResourceTicket(*this, newId, typePath);
413   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
414
415   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateMesh() New id = %u\n", newId);
416   RequestAllocateMeshMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, meshData );
417
418   return newTicket;
419 }
420
421 void ResourceClient::UpdateBitmapArea( ResourceTicketPtr ticket, RectArea& updateArea )
422 {
423   DALI_ASSERT_DEBUG( ticket );
424
425   RequestUpdateBitmapAreaMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), updateArea );
426 }
427
428 void ResourceClient::UpdateMesh( ResourceTicketPtr ticket, const Dali::MeshData& meshData )
429 {
430   DALI_ASSERT_DEBUG( ticket );
431
432   ResourcePolicy::Discardable discardable = ResourcePolicy::RETAIN;
433   if( mImpl->mDataRetentionPolicy == ResourcePolicy::DALI_DISCARDS_ALL_DATA )
434   {
435     discardable = ResourcePolicy::DISCARD;
436   }
437
438   RequestUpdateMeshMessage( mUpdateManager.GetEventToUpdate(),
439                             mResourceManager,
440                             ticket->GetId(),
441                             meshData,
442                             discardable );
443 }
444
445 Bitmap* ResourceClient::GetBitmap(ResourceTicketPtr ticket)
446 {
447   DALI_ASSERT_DEBUG( ticket );
448
449   Bitmap* bitmap = NULL;
450   BitmapCacheIter iter = mImpl->mBitmaps.find(ticket->GetId());
451
452   if( iter != mImpl->mBitmaps.end() )
453   {
454     bitmap = iter->second;
455   }
456   return bitmap;
457 }
458
459 /********************************************************************************
460  ********************   ResourceTicketLifetimeObserver methods   ****************
461  ********************************************************************************/
462
463 void ResourceClient::ResourceTicketDiscarded(const ResourceTicket& ticket)
464 {
465   const ResourceId deadId = ticket.GetId();
466   const ResourceTypePath& typePath = ticket.GetTypePath();
467
468   // Ensure associated event owned resources are also removed
469   mImpl->mBitmaps.erase(ticket.GetId());
470
471   // The ticket object is dead, remove from tickets container
472   TicketContainerSize erased = mImpl->mTickets.erase(deadId);
473   DALI_ASSERT_DEBUG(erased != 0);
474   (void)erased; // Avoid "unused variable erased" in release builds
475
476   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ResourceTicketDiscarded() deadId = %u\n", deadId);
477   RequestDiscardResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, deadId, typePath.type->id );
478 }
479
480 /********************************************************************************
481  ***********************   Notifications from ResourceManager  ******************
482  ********************************************************************************/
483
484 void ResourceClient::NotifyUploaded( ResourceId id )
485 {
486   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyUpdated(id:%u)\n", id);
487
488   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
489   if(ticketIter != mImpl->mTickets.end())
490   {
491     ResourceTicket* ticket = ticketIter->second;
492     ticket->Uploaded();
493   }
494 }
495
496 void ResourceClient::NotifySaveRequested( ResourceId id )
497 {
498   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySaveRequested(id:%u)\n", id);
499
500   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
501   if(ticketIter != mImpl->mTickets.end())
502   {
503     ResourceTicket* ticket = ticketIter->second;
504     SaveResource( ticket, "" );
505   }
506 }
507
508
509 void ResourceClient::NotifyLoading( ResourceId id )
510 {
511   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoading(id:%u)\n", id);
512
513   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
514   if(ticketIter != mImpl->mTickets.end())
515   {
516     ResourceTicket* ticket = ticketIter->second;
517     ticket->Loading();
518   }
519 }
520
521 void ResourceClient::NotifyLoadingSucceeded( ResourceId id )
522 {
523   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingSucceeded(id:%u)\n", id);
524
525   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
526   if(ticketIter != mImpl->mTickets.end())
527   {
528     ResourceTicket* ticket = ticketIter->second;
529     ticket->LoadingSucceeded();
530   }
531 }
532
533 void ResourceClient::NotifyLoadingFailed( ResourceId id )
534 {
535   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingFailed(id:%u)\n", id);
536
537   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
538   if(ticketIter != mImpl->mTickets.end())
539   {
540     ResourceTicket* ticket = ticketIter->second;
541     ticket->LoadingFailed();
542   }
543 }
544
545 void ResourceClient::NotifySavingSucceeded( ResourceId id )
546 {
547   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingSucceeded(id:%u)\n", id);
548
549   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
550   if(ticketIter != mImpl->mTickets.end())
551   {
552     ResourceTicket* ticket = ticketIter->second;
553     ticket->SavingSucceeded();
554   }
555 }
556
557 void ResourceClient::NotifySavingFailed( ResourceId id )
558 {
559   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingFailed(id:%u)\n", id);
560
561   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
562   if(ticketIter != mImpl->mTickets.end())
563   {
564     ResourceTicket* ticket = ticketIter->second;
565     ticket->SavingFailed();
566   }
567 }
568
569 void ResourceClient::UpdateImageTicket( ResourceId id, const Dali::ImageAttributes& imageAttributes ) ///!< Issue #AHC01
570 {
571   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: UpdateImageTicket(id:%u)\n", id);
572
573   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
574   if(ticketIter != mImpl->mTickets.end())
575   {
576     ResourceTicket* ticket = ticketIter->second;
577     ImageTicketPtr imageTicket = dynamic_cast<ImageTicket*>(ticket);
578     if(imageTicket)
579     {
580       imageTicket->mAttributes = imageAttributes;
581     }
582   }
583 }
584
585 } // Internal
586
587 } // Dali