Initial removal of Text 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 void ResourceClient::UpdateTexture(  ResourceId id,
407                                      BitmapUploadArray uploadArray )
408 {
409   RequestUpdateTextureMessage(  mUpdateManager.GetEventToUpdate(), mResourceManager, id, uploadArray );
410 }
411
412 ResourceTicketPtr ResourceClient::AllocateMesh( OwnerPointer<MeshData>& meshData )
413 {
414   ResourceTicketPtr newTicket;
415   const ResourceId newId = ++(mImpl->mNextId);
416   MeshResourceType meshResourceType; // construct first as no copy ctor (needed to bind ref to object)
417   ResourceTypePath typePath(meshResourceType, "");
418   newTicket = new ResourceTicket(*this, newId, typePath);
419   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
420
421   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateMesh() New id = %u\n", newId);
422   RequestAllocateMeshMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, newId, meshData );
423
424   return newTicket;
425 }
426
427 void ResourceClient::UpdateBitmapArea( ResourceTicketPtr ticket, RectArea& updateArea )
428 {
429   DALI_ASSERT_DEBUG( ticket );
430
431   RequestUpdateBitmapAreaMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), updateArea );
432 }
433
434 void ResourceClient::UpdateMesh( ResourceTicketPtr ticket, const Dali::MeshData& meshData )
435 {
436   DALI_ASSERT_DEBUG( ticket );
437
438   ResourcePolicy::Discardable discardable = ResourcePolicy::RETAIN;
439   if( mImpl->mDataRetentionPolicy == ResourcePolicy::DALI_DISCARDS_ALL_DATA )
440   {
441     discardable = ResourcePolicy::DISCARD;
442   }
443
444   RequestUpdateMeshMessage( mUpdateManager.GetEventToUpdate(),
445                             mResourceManager,
446                             ticket->GetId(),
447                             meshData,
448                             discardable );
449 }
450
451 Bitmap* ResourceClient::GetBitmap(ResourceTicketPtr ticket)
452 {
453   DALI_ASSERT_DEBUG( ticket );
454
455   Bitmap* bitmap = NULL;
456   BitmapCacheIter iter = mImpl->mBitmaps.find(ticket->GetId());
457
458   if( iter != mImpl->mBitmaps.end() )
459   {
460     bitmap = iter->second;
461   }
462   return bitmap;
463 }
464
465 /********************************************************************************
466  ********************   ResourceTicketLifetimeObserver methods   ****************
467  ********************************************************************************/
468
469 void ResourceClient::ResourceTicketDiscarded(const ResourceTicket& ticket)
470 {
471   const ResourceId deadId = ticket.GetId();
472   const ResourceTypePath& typePath = ticket.GetTypePath();
473
474   // Ensure associated event owned resources are also removed
475   mImpl->mBitmaps.erase(ticket.GetId());
476
477   // The ticket object is dead, remove from tickets container
478   TicketContainerSize erased = mImpl->mTickets.erase(deadId);
479   DALI_ASSERT_DEBUG(erased != 0);
480   (void)erased; // Avoid "unused variable erased" in release builds
481
482   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ResourceTicketDiscarded() deadId = %u\n", deadId);
483   RequestDiscardResourceMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, deadId, typePath.type->id );
484 }
485
486 /********************************************************************************
487  ***********************   Notifications from ResourceManager  ******************
488  ********************************************************************************/
489
490 void ResourceClient::NotifyUploaded( ResourceId id )
491 {
492   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyUpdated(id:%u)\n", id);
493
494   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
495   if(ticketIter != mImpl->mTickets.end())
496   {
497     ResourceTicket* ticket = ticketIter->second;
498     ticket->Uploaded();
499   }
500 }
501
502 void ResourceClient::NotifySaveRequested( ResourceId id )
503 {
504   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySaveRequested(id:%u)\n", id);
505
506   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
507   if(ticketIter != mImpl->mTickets.end())
508   {
509     ResourceTicket* ticket = ticketIter->second;
510     SaveResource( ticket, "" );
511   }
512 }
513
514
515 void ResourceClient::NotifyLoading( ResourceId id )
516 {
517   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoading(id:%u)\n", id);
518
519   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
520   if(ticketIter != mImpl->mTickets.end())
521   {
522     ResourceTicket* ticket = ticketIter->second;
523     ticket->Loading();
524   }
525 }
526
527 void ResourceClient::NotifyLoadingSucceeded( ResourceId id )
528 {
529   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingSucceeded(id:%u)\n", id);
530
531   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
532   if(ticketIter != mImpl->mTickets.end())
533   {
534     ResourceTicket* ticket = ticketIter->second;
535     ticket->LoadingSucceeded();
536   }
537 }
538
539 void ResourceClient::NotifyLoadingFailed( ResourceId id )
540 {
541   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingFailed(id:%u)\n", id);
542
543   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
544   if(ticketIter != mImpl->mTickets.end())
545   {
546     ResourceTicket* ticket = ticketIter->second;
547     ticket->LoadingFailed();
548   }
549 }
550
551 void ResourceClient::NotifySavingSucceeded( ResourceId id )
552 {
553   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingSucceeded(id:%u)\n", id);
554
555   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
556   if(ticketIter != mImpl->mTickets.end())
557   {
558     ResourceTicket* ticket = ticketIter->second;
559     ticket->SavingSucceeded();
560   }
561 }
562
563 void ResourceClient::NotifySavingFailed( ResourceId id )
564 {
565   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingFailed(id:%u)\n", id);
566
567   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
568   if(ticketIter != mImpl->mTickets.end())
569   {
570     ResourceTicket* ticket = ticketIter->second;
571     ticket->SavingFailed();
572   }
573 }
574
575 void ResourceClient::UpdateImageTicket( ResourceId id, const Dali::ImageAttributes& imageAttributes ) ///!< Issue #AHC01
576 {
577   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: UpdateImageTicket(id:%u)\n", id);
578
579   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
580   if(ticketIter != mImpl->mTickets.end())
581   {
582     ResourceTicket* ticket = ticketIter->second;
583     ImageTicketPtr imageTicket = dynamic_cast<ImageTicket*>(ticket);
584     if(imageTicket)
585     {
586       imageTicket->mAttributes = imageAttributes;
587     }
588   }
589 }
590
591 } // Internal
592
593 } // Dali