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