Merge remote-tracking branch 'origin/tizen' into new_text
[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());
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 ( NativeImageInterface& 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   newTicket->LoadingSucceeded();
329
330   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
331
332   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddNativeImage() New id = %u\n", newId);
333
334   RequestAddNativeImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, &resourceData );
335
336   return newTicket;
337 }
338
339 ImageTicketPtr ResourceClient::AddFrameBufferImage ( unsigned int width, unsigned int height, Pixel::Format pixelFormat )
340 {
341   ImageTicketPtr newTicket;
342
343   const ResourceId newId = ++(mImpl->mNextId);
344
345   Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(width, height);
346   RenderTargetResourceType renderTargetResourceType(imageAttributes) ; // construct first as no copy ctor (needed to bind ref to object)
347   ResourceTypePath typePath(renderTargetResourceType, "");
348   newTicket = new ImageTicket(*this, newId, typePath);
349   newTicket->mAttributes = imageAttributes;
350   newTicket->LoadingSucceeded();
351
352   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
353
354   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
355   RequestAddFrameBufferImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, width, height, pixelFormat );
356
357   return newTicket;
358 }
359
360 ImageTicketPtr ResourceClient::AddFrameBufferImage ( NativeImageInterface& nativeImage )
361 {
362   ImageTicketPtr newTicket;
363
364   const ResourceId newId = ++(mImpl->mNextId);
365
366   Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New(nativeImage.GetWidth(), nativeImage.GetHeight() );
367   RenderTargetResourceType renderTargetResourceType(imageAttributes); // construct first as no copy ctor (needed to bind ref to object)
368   ResourceTypePath typePath(renderTargetResourceType, "");
369   newTicket = new ImageTicket(*this, newId, typePath);
370   newTicket->mAttributes = imageAttributes;
371   newTicket->LoadingSucceeded();
372
373   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
374
375   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
376   RequestAddFrameBufferImageMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, &nativeImage );
377
378   return newTicket;
379 }
380
381
382 ResourceTicketPtr ResourceClient::AllocateTexture( unsigned int width,
383                                                    unsigned int height,
384                                                    Pixel::Format pixelformat )
385 {
386   ImageTicketPtr newTicket;
387   const ResourceId newId = ++(mImpl->mNextId);
388
389   Dali::ImageAttributes imageAttributes = Dali::ImageAttributes::New( width, height);
390   BitmapResourceType bitmapResourceType(imageAttributes); // construct first as no copy ctor (needed to bind ref to object)
391   ResourceTypePath typePath(bitmapResourceType, "");
392   newTicket = new ImageTicket(*this, newId, typePath);
393
394   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
395   newTicket->mAttributes = imageAttributes;
396   newTicket->LoadingSucceeded();
397
398   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateTexture() New id = %u\n", newId);
399
400   RequestAllocateTextureMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, width, height, pixelformat );
401
402   return newTicket;
403 }
404
405 ResourceTicketPtr ResourceClient::AllocateMesh( OwnerPointer<MeshData>& meshData )
406 {
407   ResourceTicketPtr newTicket;
408   const ResourceId newId = ++(mImpl->mNextId);
409   MeshResourceType meshResourceType; // construct first as no copy ctor (needed to bind ref to object)
410   ResourceTypePath typePath(meshResourceType, "");
411   newTicket = new ResourceTicket(*this, newId, typePath);
412   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
413
414   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateMesh() New id = %u\n", newId);
415   RequestAllocateMeshMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, meshData );
416
417   return newTicket;
418 }
419
420 void ResourceClient::UpdateBitmapArea( ResourceTicketPtr ticket, RectArea& updateArea )
421 {
422   DALI_ASSERT_DEBUG( ticket );
423
424   RequestUpdateBitmapAreaMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), updateArea );
425 }
426
427 void ResourceClient::UploadBitmap( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset )
428 {
429   RequestUploadBitmapMessage( mUpdateManager.GetEventToUpdate(),
430                               mResourceManager,
431                               destId,
432                               srcId,
433                               xOffset,
434                               yOffset );
435 }
436
437 void ResourceClient::UpdateMesh( ResourceTicketPtr ticket, const Dali::MeshData& meshData )
438 {
439   DALI_ASSERT_DEBUG( ticket );
440
441   ResourcePolicy::Discardable discardable = ResourcePolicy::RETAIN;
442   if( mImpl->mDataRetentionPolicy == ResourcePolicy::DALI_DISCARDS_ALL_DATA )
443   {
444     discardable = ResourcePolicy::DISCARD;
445   }
446
447   RequestUpdateMeshMessage( mUpdateManager.GetEventToUpdate(),
448                             mResourceManager,
449                             ticket->GetId(),
450                             meshData,
451                             discardable );
452 }
453
454 Bitmap* ResourceClient::GetBitmap(ResourceTicketPtr ticket)
455 {
456   DALI_ASSERT_DEBUG( ticket );
457
458   Bitmap* bitmap = NULL;
459   BitmapCacheIter iter = mImpl->mBitmaps.find(ticket->GetId());
460
461   if( iter != mImpl->mBitmaps.end() )
462   {
463     bitmap = iter->second;
464   }
465   return bitmap;
466 }
467
468 /********************************************************************************
469  ********************   ResourceTicketLifetimeObserver methods   ****************
470  ********************************************************************************/
471
472 void ResourceClient::ResourceTicketDiscarded(const ResourceTicket& ticket)
473 {
474   const ResourceId deadId = ticket.GetId();
475   const ResourceTypePath& typePath = ticket.GetTypePath();
476
477   // Ensure associated event owned resources are also removed
478   mImpl->mBitmaps.erase(ticket.GetId());
479
480   // The ticket object is dead, remove from tickets container
481   TicketContainerSize erased = mImpl->mTickets.erase(deadId);
482   DALI_ASSERT_DEBUG(erased != 0);
483   (void)erased; // Avoid "unused variable erased" in release builds
484
485   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ResourceTicketDiscarded() deadId = %u\n", deadId);
486   RequestDiscardResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, deadId, typePath.type->id );
487 }
488
489 /********************************************************************************
490  ***********************   Notifications from ResourceManager  ******************
491  ********************************************************************************/
492
493 void ResourceClient::NotifyUploaded( ResourceId id )
494 {
495   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyUpdated(id:%u)\n", id);
496
497   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
498   if(ticketIter != mImpl->mTickets.end())
499   {
500     ResourceTicket* ticket = ticketIter->second;
501     ticket->Uploaded();
502   }
503 }
504
505 void ResourceClient::NotifySaveRequested( ResourceId id )
506 {
507   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySaveRequested(id:%u)\n", id);
508
509   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
510   if(ticketIter != mImpl->mTickets.end())
511   {
512     ResourceTicket* ticket = ticketIter->second;
513     SaveResource( ticket, "" );
514   }
515 }
516
517
518 void ResourceClient::NotifyLoading( ResourceId id )
519 {
520   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoading(id:%u)\n", id);
521
522   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
523   if(ticketIter != mImpl->mTickets.end())
524   {
525     ResourceTicket* ticket = ticketIter->second;
526     ticket->Loading();
527   }
528 }
529
530 void ResourceClient::NotifyLoadingSucceeded( ResourceId id )
531 {
532   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingSucceeded(id:%u)\n", id);
533
534   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
535   if(ticketIter != mImpl->mTickets.end())
536   {
537     ResourceTicket* ticket = ticketIter->second;
538     ticket->LoadingSucceeded();
539   }
540 }
541
542 void ResourceClient::NotifyLoadingFailed( ResourceId id )
543 {
544   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingFailed(id:%u)\n", id);
545
546   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
547   if(ticketIter != mImpl->mTickets.end())
548   {
549     ResourceTicket* ticket = ticketIter->second;
550     ticket->LoadingFailed();
551   }
552 }
553
554 void ResourceClient::NotifySavingSucceeded( ResourceId id )
555 {
556   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingSucceeded(id:%u)\n", id);
557
558   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
559   if(ticketIter != mImpl->mTickets.end())
560   {
561     ResourceTicket* ticket = ticketIter->second;
562     ticket->SavingSucceeded();
563   }
564 }
565
566 void ResourceClient::NotifySavingFailed( ResourceId id )
567 {
568   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingFailed(id:%u)\n", id);
569
570   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
571   if(ticketIter != mImpl->mTickets.end())
572   {
573     ResourceTicket* ticket = ticketIter->second;
574     ticket->SavingFailed();
575   }
576 }
577
578 void ResourceClient::UpdateImageTicket( ResourceId id, const Dali::ImageAttributes& imageAttributes ) ///!< Issue #AHC01
579 {
580   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: UpdateImageTicket(id:%u)\n", id);
581
582   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
583   if(ticketIter != mImpl->mTickets.end())
584   {
585     ResourceTicket* ticket = ticketIter->second;
586     ImageTicketPtr imageTicket = dynamic_cast<ImageTicket*>(ticket);
587     if(imageTicket)
588     {
589       imageTicket->mAttributes = imageAttributes;
590     }
591   }
592 }
593
594 } // Internal
595
596 } // Dali