Adaptor: Fix Klocwork issues
[platform/core/uifw/dali-adaptor.git] / platform-abstractions / slp / resource-loader / resource-loader.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 // CLASS HEADER
19 #include "resource-loader.h"
20
21 // EXTERNAL HEADERS
22 #include <boost/thread.hpp>
23 #include <iostream>
24 #include <fstream>
25 #include <queue>
26
27 // INTERNAL HEADERS
28 #include <dali/integration-api/bitmap.h>
29 #include <dali/integration-api/debug.h>
30 #include <dali/integration-api/resource-cache.h>
31 #include <dali/public-api/common/dali-common.h>
32 #include <dali/public-api/common/set-wrapper.h>
33 #include <dali/public-api/math/vector2.h>
34 #include "resource-requester-base.h"
35 #include "resource-bitmap-requester.h"
36 #include "resource-model-requester.h"
37 #include "resource-shader-requester.h"
38 #include "resource-text-requester.h"
39 #include "debug/resource-loader-debug.h"
40 #include "loader-font.h"
41 #include "../interfaces/font-controller.h"
42 #include "../interfaces/data-cache.h"
43
44
45 /**
46  * A macro to expand an argument to a compile time constant string literal.
47  * Wrapping the stringify in an outer macro, means that any macro passed as
48  * "x" will be expanded before being turned into a string.
49  * Use this for example to turn the current line number into a string:
50  *   puts("The current line number is " DALI_TO_STRING(__LINE__) ".");
51  */
52 #define DALI_TO_STRING_INNER(x) #x
53 #define DALI_TO_STRING(x) DALI_TO_STRING_INNER(x)
54
55 using namespace Dali::Integration;
56 using boost::mutex;
57 using boost::unique_lock;
58 using boost::scoped_ptr;
59
60 namespace Dali
61 {
62
63 namespace SlpPlatform
64 {
65
66 namespace
67 {
68
69 const char * const DALI_USER_FONT_CACHE_PATH( DALI_USER_FONT_CACHE_DIR );
70 const unsigned int MAX_NUMBER_CHARS_TO_CACHE( 60000 );  ///< support up to 60,000 glyphs
71 const unsigned int DISTANCE_FIELD_SIZE = 64;       // doesn't need to be power of two (the atlas may for performance)
72 const unsigned int DISTANCE_FIELD_PADDING = 30;    // Number of pixels of padding around the source FreeType bitmap
73 const unsigned int HIGH_QUALITY_PIXEL_SIZE = 200;  // Pixel size sent to FreeType2 FT_Set_Char_Size() for high quality glyphs
74 const float ONE_OVER_64 = 1.0f/64.0f;
75
76 #ifdef DEBUG_ENABLED
77 // For DEBUG_ENABLED profiling of distance field glyph generation
78 double GetTimeMicroseconds()
79 {
80   timespec time;
81   clock_gettime(CLOCK_MONOTONIC, &time);
82   double seconds = time.tv_sec;
83   seconds += 1e-3 * time.tv_nsec;
84   return seconds;
85 }
86 #endif
87
88 } // unnamed namespace
89
90
91 struct ResourceLoader::ResourceLoaderImpl
92 {
93   typedef std::pair<ResourceId, ResourceRequest>  RequestStorePair;
94   typedef std::map<ResourceId, ResourceRequest>   RequestStore;
95   typedef RequestStore::iterator                  RequestStoreIter;
96
97   typedef std::queue<LoadedResource> LoadedQueue;
98   typedef std::queue<SavedResource>  SavedQueue;
99   typedef std::queue<FailedResource> FailedQueue;
100
101   typedef std::pair<ResourceTypeId, ResourceRequesterBase*> RequestHandlerPair;
102   typedef std::map<ResourceTypeId,  ResourceRequesterBase*> RequestHandlers;
103   typedef RequestHandlers::iterator                         RequestHandlersIter;
104
105   boost::mutex mQueueMutex;             ///< used to synchronize access to mLoadedQueue, mSavedQueue and mFailedQueue
106   LoadedQueue  mPartiallyLoadedQueue;   ///< Partially complete load requests notifications are stored here until fetched by core
107   LoadedQueue  mLoadedQueue;            ///< Completed load requests notifications are stored here until fetched by core
108   SavedQueue   mSavedQueue;             ///< Completed save request notifications are stored here until fetched by core
109   FailedQueue  mFailedLoads;            ///< Failed load request notifications are stored here until fetched by core
110   FailedQueue  mFailedSaves;            ///< Failed save request notifications are stored here until fetched by core
111
112   Dali::Platform::FontController* mFontController;       ///< Interface for accessing font information
113
114   RequestHandlers mRequestHandlers;
115   RequestStore mStoredRequests;         ///< Used to store load requests until loading is completed
116
117   ResourceLoaderImpl( ResourceLoader* loader )
118   {
119     mFontController = Dali::Platform::FontController::New();
120
121     mRequestHandlers.insert(std::make_pair(ResourceBitmap, new ResourceBitmapRequester(*loader)));
122     mRequestHandlers.insert(std::make_pair(ResourceShader, new ResourceShaderRequester(*loader)));
123     mRequestHandlers.insert(std::make_pair(ResourceModel, new ResourceModelRequester(*loader)));
124     mRequestHandlers.insert(std::make_pair(ResourceText, new ResourceTextRequester(*loader)));
125   }
126
127   ~ResourceLoaderImpl()
128   {
129     // Delete resource handlers
130     for( RequestHandlersIter it = mRequestHandlers.begin(); it != mRequestHandlers.end(); ++it )
131     {
132       ResourceRequesterBase* requestBase = it->second;
133       delete requestBase;
134     }
135
136     delete mFontController;
137   }
138
139   void Pause()
140   {
141     // Pause all the request handlers:
142     for( RequestHandlersIter it = mRequestHandlers.begin(), end = mRequestHandlers.end(); it != end;  ++it )
143     {
144       ResourceRequesterBase * const requester = it->second;
145       if( requester )
146       {
147         requester->Pause();
148       }
149     }
150   }
151
152   void Resume()
153   {
154     // Wake up all the request handlers:
155     for( RequestHandlersIter it = mRequestHandlers.begin(), end = mRequestHandlers.end(); it != end;  ++it )
156     {
157       ResourceRequesterBase * const requester = it->second;
158       if( requester )
159       {
160         requester->Resume();
161       }
162     }
163   }
164
165   ResourceRequesterBase* GetRequester(ResourceTypeId typeId)
166   {
167     ResourceRequesterBase* requestHandler = NULL;
168     RequestHandlersIter iter = mRequestHandlers.find(typeId);
169     if(iter != mRequestHandlers.end())
170     {
171       requestHandler = iter->second;
172     }
173     DALI_ASSERT_DEBUG(requestHandler && "All resource types should have a requester defined for them.");
174     return requestHandler;
175   }
176
177   void LoadResource(const ResourceRequest& request)
178   {
179     // Store resource request for partial loaders. Will get cleaned up after load complete has finished
180     StoreRequest(request);
181
182     ResourceRequesterBase* requester = GetRequester(request.GetType()->id);
183     if( requester )
184     {
185       ResourceRequest* storedRequest = GetRequest(request.GetId());
186       if( storedRequest != NULL )
187       {
188         requester->LoadResource(*storedRequest); // Pass in stored request
189       }
190     }
191     else
192     {
193       DALI_LOG_ERROR( "Unknown resource type (%u) with path \"%s\" in load request.\n", request.GetType()->id, request.GetPath().c_str() );
194       DALI_ASSERT_DEBUG( 0 == "Unknown resource type in load request at " __FILE__ ", line " DALI_TO_STRING(__LINE__) ".\n" );
195     }
196   }
197
198   void SaveResource(const ResourceRequest& request)
199   {
200     ResourceRequesterBase* requester = GetRequester( request.GetType()->id );
201     if( requester )
202     {
203       requester->SaveResource( request );
204     }
205   }
206
207   void CancelLoad(ResourceId id, ResourceTypeId typeId)
208   {
209     ResourceRequesterBase* requester = GetRequester(typeId);
210     if( requester )
211     {
212       requester->CancelLoad( id, typeId );
213     }
214     ClearRequest( id );
215   }
216
217   LoadStatus LoadFurtherResources( LoadedResource partialResource )
218   {
219     LoadStatus loadStatus = RESOURCE_LOADING;
220     RequestStoreIter iter = mStoredRequests.find(partialResource.id);
221
222     if( mStoredRequests.end() != iter ) // else cancelled. Ignore response
223     {
224       ResourceRequest& request = iter->second;
225       ResourceRequesterBase* requester = GetRequester(request.GetType()->id);
226       if( requester )
227       {
228         loadStatus = requester->LoadFurtherResources( request, partialResource );
229       }
230
231       DALI_LOG_INFO(gLoaderFilter, Debug::General, "ResourceLoader::LoadFurtherResources( ID:%u complete: %s)\n",  request.GetId(), loadStatus==RESOURCE_LOADING?"Loading":loadStatus==RESOURCE_PARTIALLY_LOADED?"PARTIAL":"COMPLETE" );
232     }
233
234     if( loadStatus == RESOURCE_COMPLETELY_LOADED )
235     {
236       ClearRequest( partialResource.id );
237     }
238
239     return loadStatus;
240   }
241
242   bool IsLoading()
243   {
244     // TODO - not used - remove?
245     return true;
246   }
247
248   void GetResources(ResourceCache& cache)
249   {
250     // Fill the resource cache
251
252     unique_lock<mutex> lock(mQueueMutex);
253
254     // iterate through the partially loaded resources
255     while (!mPartiallyLoadedQueue.empty())
256     {
257       LoadedResource loaded( mPartiallyLoadedQueue.front() );
258       mPartiallyLoadedQueue.pop();
259       LoadStatus loadStatus = LoadFurtherResources( loaded );
260       cache.LoadResponse( loaded.id, loaded.type, loaded.resource, loadStatus );
261     }
262
263     // iterate through the successfully loaded resources
264     while (!mLoadedQueue.empty())
265     {
266       LoadedResource loaded( mLoadedQueue.front() );
267       mLoadedQueue.pop();
268       ClearRequest( loaded.id );
269       cache.LoadResponse( loaded.id, loaded.type, loaded.resource, RESOURCE_COMPLETELY_LOADED );
270     }
271
272     // iterate through the successfully saved resources
273     while (!mSavedQueue.empty())
274     {
275       SavedResource saved(mSavedQueue.front());
276       mSavedQueue.pop();
277       cache.SaveComplete(saved.id, saved.type);
278     }
279
280     // iterate through the resources which failed to load
281     while (!mFailedLoads.empty())
282     {
283       FailedResource failed(mFailedLoads.front());
284       mFailedLoads.pop();
285       ClearRequest(failed.id);
286       cache.LoadFailed(failed.id, failed.failureType);
287     }
288
289     // iterate through the resources which failed to save
290     while (!mFailedSaves.empty())
291     {
292       FailedResource failed(mFailedSaves.front());
293       mFailedSaves.pop();
294       cache.SaveFailed(failed.id, failed.failureType);
295     }
296   }
297
298   void AddPartiallyLoadedResource( LoadedResource& resource)
299   {
300     // Lock the LoadedQueue to store the loaded resource
301     unique_lock<mutex> lock(mQueueMutex);
302
303     mPartiallyLoadedQueue.push( resource );
304   }
305
306   void AddLoadedResource(LoadedResource& resource)
307   {
308     // Lock the LoadedQueue to store the loaded resource
309     unique_lock<mutex> lock(mQueueMutex);
310
311     mLoadedQueue.push( resource );
312   }
313
314   void AddSavedResource(SavedResource& resource)
315   {
316     // Lock the SavedQueue to store the loaded resource
317     unique_lock<mutex> lock(mQueueMutex);
318
319     mSavedQueue.push(resource);
320   }
321
322   void AddFailedLoad(FailedResource& resource)
323   {
324     // Lock the FailedQueue to store the failed resource information
325     unique_lock<mutex> lock(mQueueMutex);
326
327     mFailedLoads.push(resource);
328   }
329
330   void AddFailedSave(FailedResource& resource)
331   {
332     // Lock the FailedQueue to store the failed resource information
333     unique_lock<mutex> lock(mQueueMutex);
334
335     mFailedSaves.push(resource);
336   }
337
338   void StoreRequest( const ResourceRequest& request )
339   {
340     DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader: StoreRequest(id:%u)\n", request.GetId());
341     mStoredRequests.insert( RequestStorePair( request.GetId(), request ) ); // copy request as value type
342   }
343
344   ResourceRequest* GetRequest( ResourceId id )
345   {
346     ResourceRequest* found(NULL);
347     DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader: GetRequest(id:%u)\n", id);
348     RequestStoreIter iter = mStoredRequests.find( id );
349     if( mStoredRequests.end() != iter )
350     {
351       found = &iter->second;
352     }
353     return found;
354   }
355
356   void ClearRequest( ResourceId resourceId )
357   {
358     DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader: ClearRequest(id:%u)\n", resourceId);
359     RequestStoreIter iter = mStoredRequests.find( resourceId );
360     if( mStoredRequests.end() != iter ) // Can't assert here - cancel load may cross with load failed
361     {
362       mStoredRequests.erase( iter );
363     }
364   }
365 };
366
367 /********************************************************************************/
368 /****************************   RESOURCE LOADER METHODS  ************************/
369 /********************************************************************************/
370 ResourceLoader::ResourceLoader()
371 : mTerminateThread(0)
372 {
373   mImpl = new ResourceLoaderImpl( this );
374 }
375
376 ResourceLoader::~ResourceLoader()
377 {
378   // Flag that the ResourceLoader is exiting
379   (void)__sync_or_and_fetch( &mTerminateThread, -1 );
380
381   delete mImpl;
382 }
383
384 void ResourceLoader::Pause()
385 {
386   mImpl->Pause();
387 }
388
389 void ResourceLoader::Resume()
390 {
391   mImpl->Resume();
392 }
393
394 bool ResourceLoader::IsTerminating()
395 {
396   return __sync_fetch_and_or( &mTerminateThread, 0 );
397 }
398
399 void ResourceLoader::GetResources(ResourceCache& cache)
400 {
401   mImpl->GetResources( cache );
402 }
403
404 /********************************************************************************/
405 /**************************   CALLED FROM LOADER THREADS   **********************/
406 /********************************************************************************/
407
408 void ResourceLoader::AddPartiallyLoadedResource( LoadedResource& resource)
409 {
410   mImpl->AddPartiallyLoadedResource( resource );
411 }
412
413 void ResourceLoader::AddLoadedResource(LoadedResource& resource)
414 {
415   mImpl->AddLoadedResource( resource );
416 }
417
418 void ResourceLoader::AddSavedResource(SavedResource& resource)
419 {
420   mImpl->AddSavedResource( resource );
421 }
422
423 void ResourceLoader::AddFailedLoad(FailedResource& resource)
424 {
425   mImpl->AddFailedLoad( resource );
426 }
427
428 void ResourceLoader::AddFailedSave(FailedResource& resource)
429 {
430   mImpl->AddFailedSave( resource );
431 }
432
433 /********************************************************************************/
434 /*********************   CALLED FROM PLATFORM ABSTRACTION  **********************/
435 /********************************************************************************/
436
437 void ResourceLoader::LoadResource(const ResourceRequest& request)
438 {
439   mImpl->LoadResource(request);
440 }
441
442 void ResourceLoader::SaveResource(const ResourceRequest& request)
443 {
444   mImpl->SaveResource(request);
445 }
446
447 void ResourceLoader::CancelLoad(ResourceId id, ResourceTypeId typeId)
448 {
449   mImpl->CancelLoad(id, typeId);
450 }
451
452 bool ResourceLoader::IsLoading()
453 {
454   return mImpl->IsLoading();
455 }
456
457 const std::string& ResourceLoader::GetFontFamilyForChars( const Integration::TextArray& charsRequested )
458 {
459   return mImpl->mFontController->GetFontFamilyForChars( charsRequested ).first;
460 }
461
462 bool ResourceLoader::AllGlyphsSupported( const std::string& fontFamily, const std::string& fontStyle, const Integration::TextArray& charsRequested )
463 {
464   // At this point fontFamily and fontStyle must have been validated.
465
466   return mImpl->mFontController->AllGlyphsSupported( Platform::FontController::StyledFontFamily( fontFamily, fontStyle ), charsRequested );
467 }
468
469 bool ResourceLoader::ValidateFontFamilyName( const std::string& fontFamily,
470                                              const std::string& fontStyle,
471                                              bool& isDefaultSystemFontFamily,
472                                              bool& isDefaultSystemFontStyle,
473                                              std::string& closestFontFamilyMatch,
474                                              std::string& closestFontStyleMatch )
475 {
476   Platform::FontController::StyledFontFamily closestMatch;
477
478   bool result = mImpl->mFontController->ValidateFontFamilyName( Platform::FontController::StyledFontFamily( fontFamily, fontStyle ),
479                                                                 isDefaultSystemFontFamily,
480                                                                 isDefaultSystemFontStyle,
481                                                                 closestMatch );
482
483   closestFontFamilyMatch = closestMatch.first;
484   closestFontStyleMatch = closestMatch.second;
485
486   return result;
487 }
488
489 PixelSize ResourceLoader::GetFontLineHeightFromCapsHeight( const std::string& fontFamily, const std::string& fontStyle, CapsHeight capsHeight, FT_Library freeType )
490 {
491   // At this point fontFamily and fontStyle must have been validated.
492
493   PixelSize result(0);
494
495   if (!fontFamily.empty())
496   {
497     const std::string& fontFileName = GetFontPath( fontFamily, fontStyle );
498     SlpFace* slpFace = LoadFontFace(fontFileName, PixelSize(capsHeight), freeType);
499
500     if (slpFace)
501     {
502       const float scale = static_cast<float>(capsHeight.value) / ((slpFace->face->ascender / 64.0f) * 0.95f);
503
504       result.value = static_cast<unsigned int>(roundf(scale * (slpFace->face->height / 64.0f)));
505
506       delete slpFace;
507       slpFace = NULL;
508     }
509   }
510
511   return result;
512 }
513
514 void ResourceLoader::GetFontList( Dali::Integration::PlatformAbstraction::FontListMode mode, std::vector<std::string>& fontList )
515 {
516   // VCC TODO: A GetStyles() method which returns a list of styles for a given font family is needed.
517
518   Platform::FontController::FontListMode listMode = Platform::FontController::LIST_SYSTEM_FONTS;
519
520   switch( mode )
521   {
522     case Dali::Integration::PlatformAbstraction::LIST_ALL_FONTS:
523     {
524       listMode =  Platform::FontController::LIST_ALL_FONTS;
525       break;
526     }
527     case Dali::Integration::PlatformAbstraction::LIST_SYSTEM_FONTS:
528     {
529       listMode =  Platform::FontController::LIST_SYSTEM_FONTS;
530       break;
531     }
532     case Dali::Integration::PlatformAbstraction::LIST_APPLICATION_FONTS:
533     {
534       listMode =  Platform::FontController::LIST_APPLICATION_FONTS;
535       break;
536     }
537     default:
538     {
539       DALI_ASSERT_DEBUG( false && "invalid mode" );
540     }
541   }
542
543   Platform::FontController::FontList styledFontList;
544   mImpl->mFontController->GetFontList( listMode, styledFontList );
545
546   std::set<std::string> uniqueFontNames;
547   for( Platform::FontController::FontList::const_iterator it = styledFontList.begin(), endIt = styledFontList.end(); it != endIt; ++it )
548   {
549     uniqueFontNames.insert( it->first );
550   }
551
552   // copy into a vector
553   std::copy( uniqueFontNames.begin(), uniqueFontNames.end(), std::back_inserter( fontList ) );
554 }
555
556
557 /**
558  * Note, called from both platform abstraction & from text loader threads
559  **/
560 GlyphSet* ResourceLoader::GetGlyphData (const TextResourceType& textRequest,
561                                         FT_Library freeType,
562                                         const std::string& fontFamily,
563                                         bool getBitmap)
564 {
565   // At this point fontFamily and the font style stored in the textRequest must have been validated.
566
567   GlyphSet* glyphSet = NULL;
568
569   size_t fontHash = textRequest.mFontHash;
570
571   DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "LoadGlyphSet - requested string is %d characters long\n", textRequest.mCharacterList.size());
572
573   // path holds the font name
574   if( !fontFamily.empty() )
575   {
576     const std::string& fontFileName = GetFontPath( fontFamily, textRequest.mStyle );
577
578     const bool highQuality(textRequest.mQuality == TextResourceType::TextQualityHigh);
579     const unsigned int glyphQuality( highQuality ? GlyphMetrics::HIGH_QUALITY : GlyphMetrics::LOW_QUALITY );
580
581     SlpFace* slpFace = LoadFontFace( fontFileName, PixelSize( HIGH_QUALITY_PIXEL_SIZE), freeType );
582     if (slpFace)
583     {
584       glyphSet = new GlyphSet();
585       glyphSet->mFontHash = fontHash;
586       glyphSet->SetAtlasResourceId( textRequest.mTextureAtlasId );
587
588       for( TextResourceType::CharacterList::const_iterator it = textRequest.mCharacterList.begin(), endIt = textRequest.mCharacterList.end(); it != endIt; ++it )
589       {
590         uint32_t charCode( it->character );
591
592         if (!glyphSet->HasCharacter(charCode))        // ignore duplicate glyphs in the request
593         {
594 #ifdef DEBUG_ENABLED
595           // DEBUG_ENABLED profiling of distance field glyph generation
596           double then( 0.0 );
597           if( getBitmap )
598           {
599             then = GetTimeMicroseconds();
600           }
601 #endif
602           scoped_ptr< GlyphSet::Character > character( GetCharacter(slpFace->face, charCode,
603                                                                     DISTANCE_FIELD_SIZE, DISTANCE_FIELD_PADDING, textRequest.mMaxGlyphSize,
604                                                                     getBitmap, highQuality ) );
605
606 #ifdef DEBUG_ENABLED
607           // DEBUG_ENABLED profiling of distance field glyph generation
608           if( getBitmap )
609           {
610             double now( GetTimeMicroseconds() );
611
612             DALI_LOG_INFO( gLoaderFilter, Log::Verbose, "Generating (%c) in %s quality took %.3f ms\n", charCode, highQuality ? "high" : "low",  1e-3 * ( now - then ) );
613           }
614 #endif
615           if (character)
616           {
617             GlyphSet::Character& glyphCharacter( *character.get() );
618
619             glyphCharacter.second.quality = glyphQuality;
620             glyphCharacter.second.xPosition = it->xPosition;
621             glyphCharacter.second.yPosition = it->yPosition;
622             // copy character to GlyphSet
623             glyphSet->AddCharacter( glyphCharacter );
624           }
625         }
626       }
627
628       delete slpFace;
629     }
630   }
631
632   return glyphSet;
633 }
634
635 GlyphSet* ResourceLoader::GetCachedGlyphData(const TextResourceType& textRequest, const std::string& fontFamily)
636 {
637   GlyphSet* glyphSet( new GlyphSet() );
638   glyphSet->mFontHash = textRequest.mFontHash;
639   glyphSet->SetAtlasResourceId(textRequest.mTextureAtlasId);
640
641   std::string cachePath(DALI_USER_FONT_CACHE_PATH);
642   cachePath.append(fontFamily + "-" + textRequest.mStyle);
643   std::replace(cachePath.begin(), cachePath.end(), ' ', '-');
644
645   DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::GetCachedGlyphData() - cachefile: %s\n", cachePath.c_str() );
646
647   Platform::DataCache* dataCache = Platform::DataCache::New( Platform::DataCache::READ_ONLY,
648                                                              Platform::DataCache::RUN_LENGTH_ENCODING,
649                                                              cachePath,
650                                                              DISTANCE_FIELD_SIZE * DISTANCE_FIELD_SIZE,
651                                                              MAX_NUMBER_CHARS_TO_CACHE);
652
653   Platform::DataCache::KeyVector keyVector;
654   Platform::DataCache::DataVector dataVector;
655
656   const TextResourceType::CharacterList& requestedCharacters = textRequest.mCharacterList;
657   for( std::size_t i=0, length = requestedCharacters.size(); i < length; ++i )
658   {
659     keyVector.push_back( requestedCharacters[i].character );
660   }
661
662   // load the glyphs from file
663   dataCache->Find( keyVector, dataVector );
664
665   // for each glyph found, add to the glyph set
666   for( std::size_t n = 0, arraySize = keyVector.size(); n < arraySize ; n++ )
667   {
668     Platform::DataCache::Data& data( dataVector[n]);
669
670     if( data.exists )
671     {
672       GlyphMetrics glyphMetrics;
673       glyphMetrics.code = keyVector[ n ];
674       glyphMetrics.quality = GlyphMetrics::HIGH_QUALITY;
675       glyphMetrics.xPosition = requestedCharacters[n].xPosition;
676       glyphMetrics.yPosition = requestedCharacters[n].yPosition;
677
678       // create a new bitmap, and copy in the data
679       BitmapPtr bitmapData ( Integration::Bitmap::New(Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::DISCARD) );
680
681       // assign the data
682       bitmapData->GetPackedPixelsProfile()->AssignBuffer( Pixel::A8, data.data, DISTANCE_FIELD_SIZE * DISTANCE_FIELD_SIZE, DISTANCE_FIELD_SIZE, DISTANCE_FIELD_SIZE );
683
684       data.data = NULL;
685
686       // add to the glyphset
687       glyphSet->AddCharacter( bitmapData, glyphMetrics );
688     }
689   }
690   DALI_LOG_INFO( gLoaderFilter, Debug::Verbose, "ResourceLoader::GetCachedGlyphData() - requestedGlyphs:%u, cachedGlyphs:%u\n",
691                  requestedCharacters.size(), glyphSet->GetCharacterList().size() );
692
693   delete dataCache;
694
695   return glyphSet;
696 }
697
698 void ResourceLoader::GetGlobalMetrics( FT_Library freeType,
699                                        const std::string& fontFamily,
700                                        const std::string& fontStyle,
701                                        GlobalMetrics& globalMetrics )
702 {
703   // At this point fontFamily and fontStyle must have been validated.
704
705   if( !fontFamily.empty() )
706   {
707     const std::string& fontFileName = GetFontPath( fontFamily, fontStyle );
708
709     SlpFace* slpFace = LoadFontFace( fontFileName, PixelSize( HIGH_QUALITY_PIXEL_SIZE), freeType );
710     if( slpFace )
711     {
712       // scale factor for unit scaled glyphs
713       const float xScale = 1.0f / (slpFace->face->size->metrics.x_scale / 65536.0f);
714       const float yScale = 1.0f / (slpFace->face->size->metrics.y_scale / 65536.0f);
715
716       globalMetrics.lineHeight = slpFace->face->height * ONE_OVER_64;
717       globalMetrics.ascender = slpFace->face->ascender * ONE_OVER_64;
718       globalMetrics.unitsPerEM = slpFace->face->units_per_EM * ONE_OVER_64;
719
720       globalMetrics.underlinePosition = -4.f;
721       globalMetrics.underlineThickness = 5.f * yScale;
722       if( 1.f > globalMetrics.underlineThickness )
723       {
724         globalMetrics.underlineThickness = 1.f;
725       }
726       globalMetrics.maxWidth = DISTANCE_FIELD_SIZE * xScale;
727       globalMetrics.maxHeight = DISTANCE_FIELD_SIZE * yScale;
728       globalMetrics.padAdjustX = DISTANCE_FIELD_PADDING * xScale;
729       globalMetrics.padAdjustY = DISTANCE_FIELD_PADDING * yScale;
730
731       delete slpFace;
732     }
733   }
734 }
735
736 void ResourceLoader::SetDpi(unsigned int dpiHor, unsigned int dpiVer)
737 {
738   // Unused
739 }
740
741 bool ResourceLoader::LoadFile( const std::string& filename, std::vector< unsigned char >& buffer ) const
742 {
743   DALI_LOG_TRACE_METHOD(gLoaderFilter);
744
745   DALI_ASSERT_DEBUG( 0 != filename.length());
746
747   bool result;
748
749   std::filebuf buf;
750   buf.open(filename.c_str(), std::ios::in | std::ios::binary);
751   if( buf.is_open() )
752   {
753     std::istream stream(&buf);
754
755     // determine data length
756     stream.seekg(0, std::ios_base::end);
757     unsigned int length = static_cast<unsigned int>( stream.tellg() );
758     stream.seekg(0, std::ios_base::beg);
759
760     // allocate a buffer
761     buffer.resize(length);
762     // read data into buffer
763     stream.read(reinterpret_cast<char*>(buffer.data()), length);
764
765     DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::LoadFile(%s) - loaded %d bytes\n", filename.c_str(), length);
766
767     result = true;
768   }
769   else
770   {
771     DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::LoadFile(%s) - failed to load\n", filename.c_str());
772     result = false;
773   }
774
775   return result;
776 }
777
778 std::string ResourceLoader::LoadFile(const std::string& filename) const
779 {
780   DALI_LOG_TRACE_METHOD(gLoaderFilter);
781
782   DALI_ASSERT_DEBUG( 0 != filename.length());
783
784   std::string contents;
785
786   std::filebuf buf;
787   buf.open(filename.c_str(), std::ios::in);
788   if( buf.is_open() )
789   {
790     std::istream stream(&buf);
791
792     // determine data length
793     stream.seekg(0, std::ios_base::end);
794     unsigned int length = static_cast<unsigned int>( stream.tellg() );
795     stream.seekg(0, std::ios_base::beg);
796
797     // allocate a buffer
798     contents.resize(length);
799     // read data into buffer
800     stream.read(&contents[0], length);
801
802     DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::LoadFile(%s) - loaded %d bytes\n", filename.c_str(), length);
803   }
804   else
805   {
806     DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::LoadFile(%s) - failed to load\n", filename.c_str());
807   }
808
809   return contents;
810 }
811
812 bool ResourceLoader::SaveFile(const std::string& filename, std::vector< unsigned char >& buffer)
813 {
814   DALI_LOG_TRACE_METHOD(gLoaderFilter);
815
816   DALI_ASSERT_DEBUG( 0 != filename.length());
817
818   bool result = false;
819
820   std::filebuf buf;
821   buf.open(filename.c_str(), std::ios::out | std::ios_base::trunc | std::ios::binary);
822   if( buf.is_open() )
823   {
824     std::ostream stream(&buf);
825
826     // determine size of buffer
827     int length = static_cast<int>(buffer.size());
828
829     // write contents of buffer to the file
830     stream.write(reinterpret_cast<char*>(buffer.data()), length);
831
832     if( !stream.bad() )
833     {
834       DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::SaveFile(%s) - wrote %d bytes\n", filename.c_str(), length);
835       result = true;
836     }
837   }
838
839 #if defined(DEBUG_BUILD)
840   if( !result )
841   {
842     DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::SaveFile(%s) - failed to load\n", filename.c_str());
843   }
844 #endif
845
846   return result;
847 }
848
849 Integration::BitmapPtr ResourceLoader::GetGlyphImage( FT_Library freeType, const std::string& fontFamily, const std::string& fontStyle, float fontSize, uint32_t character )
850 {
851   // At this point fontFamily and fontStyle must have been validated.
852
853   Integration::BitmapPtr image;
854
855   const std::string& fontFileName = GetFontPath( fontFamily, fontStyle );
856   SlpFace* slpFace = LoadFontFace( fontFileName, PixelSize( Font::PointsToPixels( fontSize ) ), freeType );
857
858   if( NULL != slpFace )
859   {
860     image = GetGlyphBitmap( slpFace->face, character );
861     delete slpFace;
862   }
863
864   return image;
865 }
866
867 void ResourceLoader::SetDefaultFontFamily( const std::string& fontFamily, const std::string& fontStyle )
868 {
869   mImpl->mFontController->SetDefaultFontFamily( Platform::FontController::StyledFontFamily( fontFamily, fontStyle ) );
870 }
871
872 const std::string& ResourceLoader::GetFontPath(const std::string& fontFamily, const std::string& fontStyle)
873 {
874   // At this point fontFamily and fontStyle must have been validated.
875   return mImpl->mFontController->GetFontPath(std::make_pair(fontFamily,fontStyle));
876 }
877
878 } // namespace SlpPlatform
879
880 } // namespace Dali