Remove ImageAttributes from public API
[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/event-thread-services.h>
26 #include <dali/internal/event/common/stage-impl.h>
27 #include <dali/internal/event/images/image-impl.h>
28 #include <dali/internal/update/resources/resource-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                                 EventThreadServices& eventThreadServices,
61                                 ResourcePolicy::DataRetention dataRetentionPolicy)
62 : mResourceManager(resourceManager),
63   mEventThreadServices(eventThreadServices)
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.Reset( bitmapResource.size, bitmapResource.scalingMode, bitmapResource.samplingMode, bitmapResource.orientationCorrection );
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.SetSize( nativeResource.imageDimensions.GetWidth(), nativeResource.imageDimensions.GetHeight() );
118       newTicket = imageTicket;
119       break;
120     }
121     case ResourceTargetImage:
122     case ResourceShader:
123     case ResourceMesh:
124     {
125       newTicket = new ResourceTicket(*this, newId, typePath);
126       break;
127     }
128   }
129
130   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
131
132   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResource(path:%s type.id:%d) newId:%u\n", path.c_str(), type.id, newId);
133
134   RequestLoadResourceMessage( mEventThreadServices, mResourceManager, newId, typePath, priority );
135   return newTicket;
136 }
137
138 ResourceTicketPtr ResourceClient::DecodeResource(
139   const ResourceType& type,
140   RequestBufferPtr buffer,
141   LoadResourcePriority priority )
142 {
143   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" );
144   DALI_ASSERT_DEBUG( buffer.Get() && "Null resource buffer passed for decoding." );
145   ResourceTicketPtr newTicket;
146   if( buffer.Get() ) //< Check to avoid SEGV on a null pointer.
147   {
148     ResourceTypePath typePath( type, "" );
149     ResourceId newId = 0;
150
151     // Create the correct ticket type for the resource:
152     switch (type.id)
153     {
154       case ResourceBitmap:
155       {
156         // NOTE: pre-increment, otherwise we get 0 for first one.
157         newId = ++(mImpl->mNextId);
158         const BitmapResourceType& bitmapResource = static_cast <const BitmapResourceType&> ( type );
159         // Image tickets will cache the requested parameters, which are updated on successful loading
160         ImageTicket* imageTicket = new ImageTicket( *this, newId, typePath );
161         imageTicket->mAttributes.Reset( bitmapResource.size, bitmapResource.scalingMode, bitmapResource.samplingMode, bitmapResource.orientationCorrection );;
162         newTicket = imageTicket;
163         break;
164       }
165
166       // FALLTHROUGH:
167       case ResourceNativeImage:
168       case ResourceTargetImage:
169       case ResourceShader:
170       case ResourceMesh:
171       {
172         DALI_LOG_ERROR( "Unsupported resource type passed for decoding from a memory buffer." );
173       }
174     }
175
176     if( newTicket )
177     {
178       mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
179       DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: DecodeResource( type.id:%d ) newId:%u\n", type.id, newId);
180
181       RequestDecodeResourceMessage( mEventThreadServices, mResourceManager, newId, typePath, buffer, priority );
182     }
183   }
184   return newTicket;
185 }
186
187 ResourceTicketPtr ResourceClient::LoadShader( ShaderResourceType& type,
188                                               const std::string& path )
189 {
190   ResourceTicketPtr newTicket;
191
192   const ResourceId newId = ++(mImpl->mNextId);
193
194   ResourceTypePath typePath(type, path);
195   newTicket = new ResourceTicket(*this, newId, typePath);
196
197   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
198
199   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: LoadShader(path:%s) newId:%u\n", path.c_str(), newId);
200
201   RequestLoadShaderMessage( mEventThreadServices, mResourceManager, newId, typePath );
202   return newTicket;
203 }
204
205 bool ResourceClient::ReloadResource( ResourceId id, bool resetFinishedStatus, LoadResourcePriority priority )
206 {
207   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ReloadResource(Id: %u)\n", id);
208
209   bool resourceExists = false;
210   TicketContainerIter ticketIter;
211   ticketIter = mImpl->mTickets.find(id);
212
213   if(ticketIter != mImpl->mTickets.end())
214   {
215     resourceExists = true;
216     // The ticket is already being observed
217     ResourceTicket* ticket = ticketIter->second;
218     DALI_ASSERT_DEBUG(ticket && "Null ticket for tracked resource request." );
219     const ResourceTypePath * const typePathPtr = &ticket->GetTypePath();
220     DALI_ASSERT_DEBUG( typePathPtr );
221     RequestReloadResourceMessage( mEventThreadServices, mResourceManager, id, *typePathPtr, priority, resetFinishedStatus );
222   }
223   else
224   {
225     DALI_LOG_ERROR ("Resource %d does not exist\n", id);
226   }
227   return resourceExists;
228 }
229
230 void ResourceClient::SaveResource( ResourceTicketPtr ticket, const std::string& url )
231 {
232   DALI_ASSERT_DEBUG( ticket );
233
234   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: SaveResource(Id: %u, path:%s)\n", ticket->GetId(), url.c_str());
235
236   const ResourceTypePath * const typePathPtr = &ticket->GetTypePath();
237   if( typePathPtr )
238   {
239     if( 0 != url.length() )
240     {
241       ResourceTypePath typePath( *(typePathPtr->type), url );
242       RequestSaveResourceMessage( mEventThreadServices, mResourceManager, ticket->GetId(), typePath );
243     }
244     else
245     {
246       ResourceTypePath typePath( *typePathPtr );
247       RequestSaveResourceMessage( mEventThreadServices, mResourceManager, ticket->GetId(), typePath );
248     }
249   }
250 }
251
252 ResourceTicketPtr ResourceClient::RequestResourceTicket( ResourceId id )
253 {
254   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: RequestResourceTicket(Id: %u)\n", id);
255
256   ResourceTicketPtr ticket;
257
258   TicketContainerIter ticketIter = mImpl->mTickets.find( id );
259
260   if ( mImpl->mTickets.end() != ticketIter )
261   {
262     ticket = ticketIter->second;
263   }
264
265   return ticket;
266 }
267
268 ImageTicketPtr ResourceClient::AllocateBitmapImage( unsigned int width,
269                                                     unsigned int height,
270                                                     unsigned int bufferWidth,
271                                                     unsigned int bufferHeight,
272                                                     Pixel::Format pixelformat )
273 {
274   /* buffer is available via public-api, therefore not discardable */
275   Bitmap* const bitmap = Bitmap::New( Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::RETAIN );
276   Bitmap::PackedPixelsProfile* const packedBitmap = bitmap->GetPackedPixelsProfile();
277   DALI_ASSERT_DEBUG(packedBitmap);
278
279   packedBitmap->ReserveBuffer(pixelformat, width, height, bufferWidth, bufferHeight);
280   DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
281   DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
282
283   ImageTicketPtr ticket = AddBitmapImage(bitmap);
284
285   DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
286   DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
287   return ticket;
288 }
289
290 ImageTicketPtr ResourceClient::AddBitmapImage(Bitmap* bitmap)
291 {
292   DALI_ASSERT_DEBUG( bitmap != NULL );
293
294   ImageTicketPtr newTicket;
295
296   const ResourceId newId = ++(mImpl->mNextId);
297
298   ImageAttributes imageAttributes = ImageAttributes::New(bitmap->GetImageWidth(), bitmap->GetImageHeight());
299   BitmapResourceType bitmapResourceType( ImageDimensions::FromFloatVec2( imageAttributes.GetSize() ) ); // construct first as no copy ctor (needed to bind ref to object)
300   ResourceTypePath typePath(bitmapResourceType, "");
301   newTicket = new ImageTicket(*this, newId, typePath);
302   newTicket->mAttributes = imageAttributes;
303   newTicket->LoadingSucceeded();
304
305   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
306
307   // Store bitmap for immediate access.
308   mImpl->mBitmaps[newId] = bitmap;
309
310   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddBitmapImage() New id = %u\n", newId);
311   RequestAddBitmapImageMessage( mEventThreadServices, mResourceManager, newId, bitmap );
312
313   return newTicket;
314 }
315
316 ResourceTicketPtr ResourceClient::AddNativeImage ( NativeImageInterface& resourceData )
317 {
318   ImageTicketPtr newTicket;
319
320   const ResourceId newId = ++(mImpl->mNextId);
321   NativeImageResourceType nativeImageResourceType; // construct first as no copy ctor (needed to bind ref to object)
322   ResourceTypePath typePath(nativeImageResourceType, "");
323   newTicket = new ImageTicket(*this, newId, typePath);
324   newTicket->mAttributes = ImageAttributes::New(resourceData.GetWidth(),
325                                                 resourceData.GetHeight());
326   newTicket->LoadingSucceeded();
327
328   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
329
330   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddNativeImage() New id = %u\n", newId);
331
332   RequestAddNativeImageMessage( mEventThreadServices, mResourceManager, newId, &resourceData );
333
334   return newTicket;
335 }
336
337 ImageTicketPtr ResourceClient::AddFrameBufferImage ( unsigned int width, unsigned int height, Pixel::Format pixelFormat )
338 {
339   ImageTicketPtr newTicket;
340
341   const ResourceId newId = ++(mImpl->mNextId);
342
343   ImageAttributes imageAttributes = ImageAttributes::New(width, height);
344   RenderTargetResourceType renderTargetResourceType( ImageDimensions( width, height ) ); // construct first as no copy ctor (needed to bind ref to object)
345   ResourceTypePath typePath(renderTargetResourceType, "");
346   newTicket = new ImageTicket(*this, newId, typePath);
347   newTicket->mAttributes = imageAttributes;
348   newTicket->LoadingSucceeded();
349
350   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
351
352   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
353   RequestAddFrameBufferImageMessage( mEventThreadServices, mResourceManager, newId, width, height, pixelFormat );
354
355   return newTicket;
356 }
357
358 ImageTicketPtr ResourceClient::AddFrameBufferImage ( NativeImageInterface& nativeImage )
359 {
360   ImageTicketPtr newTicket;
361
362   const ResourceId newId = ++(mImpl->mNextId);
363
364   ImageAttributes imageAttributes = ImageAttributes::New( nativeImage.GetWidth(), nativeImage.GetHeight() );
365   RenderTargetResourceType renderTargetResourceType( ImageDimensions( nativeImage.GetWidth(), nativeImage.GetHeight() ) ); // construct first as no copy ctor (needed to bind ref to object)
366   ResourceTypePath typePath(renderTargetResourceType, "");
367   newTicket = new ImageTicket(*this, newId, typePath);
368   newTicket->mAttributes = imageAttributes;
369   newTicket->LoadingSucceeded();
370
371   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
372
373   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddFrameBufferImage() New id = %u\n", newId);
374   RequestAddFrameBufferImageMessage( mEventThreadServices, mResourceManager, newId, &nativeImage );
375
376   return newTicket;
377 }
378
379
380 ResourceTicketPtr ResourceClient::AllocateTexture( unsigned int width,
381                                                    unsigned int height,
382                                                    Pixel::Format pixelformat )
383 {
384   ImageTicketPtr newTicket;
385   const ResourceId newId = ++(mImpl->mNextId);
386
387   ImageAttributes imageAttributes = ImageAttributes::New( width, height);
388   BitmapResourceType bitmapResourceType( ImageDimensions( width, height ) ); // construct first as no copy ctor (needed to bind ref to object)
389   ResourceTypePath typePath(bitmapResourceType, "");
390   newTicket = new ImageTicket(*this, newId, typePath);
391
392   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
393   newTicket->mAttributes = imageAttributes;
394   newTicket->LoadingSucceeded();
395
396   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateTexture() New id = %u\n", newId);
397
398   RequestAllocateTextureMessage( mEventThreadServices, mResourceManager, newId, width, height, pixelformat );
399
400   return newTicket;
401 }
402
403 ResourceTicketPtr ResourceClient::AllocateMesh( OwnerPointer<MeshData>& meshData )
404 {
405   ResourceTicketPtr newTicket;
406   const ResourceId newId = ++(mImpl->mNextId);
407   MeshResourceType meshResourceType; // construct first as no copy ctor (needed to bind ref to object)
408   ResourceTypePath typePath(meshResourceType, "");
409   newTicket = new ResourceTicket(*this, newId, typePath);
410   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
411
412   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AllocateMesh() New id = %u\n", newId);
413   RequestAllocateMeshMessage( mEventThreadServices, mResourceManager, newId, meshData );
414
415   return newTicket;
416 }
417
418 void ResourceClient::UpdateBitmapArea( ResourceTicketPtr ticket, RectArea& updateArea )
419 {
420   DALI_ASSERT_DEBUG( ticket );
421
422   RequestUpdateBitmapAreaMessage( mEventThreadServices, mResourceManager, ticket->GetId(), updateArea );
423 }
424
425 void ResourceClient::UploadBitmap( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset )
426 {
427   RequestUploadBitmapMessage( mEventThreadServices,
428                               mResourceManager,
429                               destId,
430                               srcId,
431                               xOffset,
432                               yOffset );
433 }
434
435
436 void ResourceClient::UploadBitmap( ResourceId destId,Integration::BitmapPtr bitmap, std::size_t xOffset, std::size_t yOffset)
437 {
438   RequestUploadBitmapMessage( mEventThreadServices,
439                               mResourceManager,
440                               destId,
441                               bitmap,
442                               xOffset,
443                               yOffset );
444 }
445
446 void ResourceClient::UpdateMesh( ResourceTicketPtr ticket, const Dali::MeshData& meshData )
447 {
448   DALI_ASSERT_DEBUG( ticket );
449
450   ResourcePolicy::Discardable discardable = ResourcePolicy::RETAIN;
451   if( mImpl->mDataRetentionPolicy == ResourcePolicy::DALI_DISCARDS_ALL_DATA )
452   {
453     discardable = ResourcePolicy::DISCARD;
454   }
455
456   RequestUpdateMeshMessage( mEventThreadServices,
457                             mResourceManager,
458                             ticket->GetId(),
459                             meshData,
460                             discardable );
461 }
462
463 Bitmap* ResourceClient::GetBitmap(ResourceTicketPtr ticket)
464 {
465   DALI_ASSERT_DEBUG( ticket );
466
467   Bitmap* bitmap = NULL;
468   BitmapCacheIter iter = mImpl->mBitmaps.find(ticket->GetId());
469
470   if( iter != mImpl->mBitmaps.end() )
471   {
472     bitmap = iter->second;
473   }
474   return bitmap;
475 }
476
477 /********************************************************************************
478  ********************   ResourceTicketLifetimeObserver methods   ****************
479  ********************************************************************************/
480
481 void ResourceClient::ResourceTicketDiscarded(const ResourceTicket& ticket)
482 {
483   const ResourceId deadId = ticket.GetId();
484   const ResourceTypePath& typePath = ticket.GetTypePath();
485
486   // Ensure associated event owned resources are also removed
487   mImpl->mBitmaps.erase(ticket.GetId());
488
489   // The ticket object is dead, remove from tickets container
490   TicketContainerSize erased = mImpl->mTickets.erase(deadId);
491   DALI_ASSERT_DEBUG(erased != 0);
492   (void)erased; // Avoid "unused variable erased" in release builds
493
494   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ResourceTicketDiscarded() deadId = %u\n", deadId);
495   RequestDiscardResourceMessage( mEventThreadServices, mResourceManager, deadId, typePath.type->id );
496 }
497
498 /********************************************************************************
499  ***********************   Notifications from ResourceManager  ******************
500  ********************************************************************************/
501
502 void ResourceClient::NotifyUploaded( ResourceId id )
503 {
504   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyUpdated(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     ticket->Uploaded();
511   }
512 }
513
514 void ResourceClient::NotifySaveRequested( ResourceId id )
515 {
516   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySaveRequested(id:%u)\n", id);
517
518   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
519   if(ticketIter != mImpl->mTickets.end())
520   {
521     ResourceTicket* ticket = ticketIter->second;
522     SaveResource( ticket, "" );
523   }
524 }
525
526
527 void ResourceClient::NotifyLoading( ResourceId id )
528 {
529   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoading(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->Loading();
536   }
537 }
538
539 void ResourceClient::NotifyLoadingSucceeded( ResourceId id )
540 {
541   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingSucceeded(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->LoadingSucceeded();
548   }
549 }
550
551 void ResourceClient::NotifyLoadingFailed( ResourceId id )
552 {
553   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifyLoadingFailed(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->LoadingFailed();
560   }
561 }
562
563 void ResourceClient::NotifySavingSucceeded( ResourceId id )
564 {
565   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingSucceeded(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->SavingSucceeded();
572   }
573 }
574
575 void ResourceClient::NotifySavingFailed( ResourceId id )
576 {
577   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: NotifySavingFailed(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     ticket->SavingFailed();
584   }
585 }
586
587 void ResourceClient::UpdateImageTicket( ResourceId id, const ImageAttributes& imageAttributes ) ///!< Issue #AHC01
588 {
589   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: UpdateImageTicket(id:%u)\n", id);
590
591   TicketContainerIter ticketIter = mImpl->mTickets.find(id);
592   if(ticketIter != mImpl->mTickets.end())
593   {
594     ResourceTicket* ticket = ticketIter->second;
595     ImageTicketPtr imageTicket = dynamic_cast<ImageTicket*>(ticket);
596     if(imageTicket)
597     {
598       imageTicket->mAttributes = imageAttributes;
599     }
600   }
601 }
602
603 } // Internal
604
605 } // Dali