Adaptor: Fix Klocwork issues
[platform/core/uifw/dali-adaptor.git] / platform-abstractions / slp / font-platform / font-controller-impl.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 "font-controller-impl.h"
20
21 // INTERNAL HEADERS
22 #include <dali/public-api/common/dali-common.h>
23 #include <dali/integration-api/debug.h>
24
25 // EXTERNAL HEADERS
26 #include <fontconfig/fontconfig.h>
27
28
29 namespace Dali
30 {
31
32 namespace SlpPlatform
33 {
34
35 #if defined(DEBUG_ENABLED)
36 namespace
37 {
38 Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::Concise, false, "LOG_FONT_CONTROLLER");
39 } // unnamed namespace
40 #endif
41
42 namespace
43 {
44 const std::string SETTING_FONT_PRELOAD_FONT_PATH( FONT_PRELOADED_PATH );
45 const std::string SETTING_FONT_DOWNLOADED_FONT_PATH( FONT_DOWNLOADED_PATH );
46 const std::string SETTING_FONT_APP_FONT_PATH( FONT_APPLICATION_PATH );
47
48 const uint32_t UNICODE_CR_LF = 0x85;
49 const uint32_t UNICODE_CHAR_START = 0x20;       // start range of unicode characters (below are control chars)
50 const std::string FONT_FORMAT( "TrueType" );
51 const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
52 const std::string DEFAULT_FONT_STYLE( "Regular" );
53
54 const std::string NULL_FONT_FAMILY_NAME( "" );
55 const FontController::StyledFontFamily NULL_STYLED_FONT_FAMILY( std::make_pair( NULL_FONT_FAMILY_NAME, std::string( "" ) ) );
56
57 /**
58  * @param[in] pattern pointer to a font config pattern
59  * @param[out] familyName font family name or an empty string if the font is not found.
60  * @return Whether a font is found.
61  */
62 bool GetFontFamily( const FcPattern* pattern, std::string& familyName )
63 {
64   FcChar8* family = NULL;
65   const FcResult retVal = FcPatternGetString( pattern, FC_FAMILY, 0u, &family );
66
67   if( FcResultMatch != retVal )
68   {
69     familyName.clear();
70     return false;
71   }
72
73   // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
74   familyName.assign( reinterpret_cast<const char*>( family ) );
75
76   return true;
77 }
78
79 /**
80  * @param[in] pattern pointer to a font config pattern
81  * @param[out] fontStyle font style name or an empty string if the font has no style.
82  * @return Whether a font style is found.
83  */
84 bool GetFontStyle( const FcPattern* pattern, std::string& fontStyle )
85 {
86   FcChar8* style = NULL;
87   const FcResult retVal = FcPatternGetString( pattern, FC_STYLE, 0u, &style );
88
89   if( FcResultMatch != retVal)
90   {
91     // Has no style.
92     fontStyle.clear();
93     return false;
94   }
95
96   // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
97   fontStyle.assign( reinterpret_cast<const char*>( style ) );
98
99   return true;
100 }
101
102 /**
103  * @param[in] pattern pointer to a font config pattern
104  * @param[out] fileName font file name or an empty string if the font is not found.
105  * @return Whether a font is found.
106  */
107 bool GetFileName( const FcPattern* pattern, std::string& fileName )
108 {
109   FcChar8* file = NULL;
110   const FcResult retVal = FcPatternGetString( pattern, FC_FILE, 0u, &file );
111
112   if( FcResultMatch != retVal )
113   {
114     // Has no file name.
115     fileName.clear();
116     return false;
117   }
118
119   // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
120   fileName.assign( reinterpret_cast<const char*>( file ) );
121
122   return true;
123 }
124
125 bool CheckFontInstallPath( FontController::FontListMode listMode, const std::string& fileName )
126 {
127   switch( listMode )
128   {
129     case FontController::LIST_SYSTEM_FONTS:
130     {
131       const std::string& preloadPath( SETTING_FONT_PRELOAD_FONT_PATH );
132       const std::string& downloadPath( SETTING_FONT_DOWNLOADED_FONT_PATH );
133       const std::size_t preloadLength = preloadPath.length();
134       const std::size_t downloadLength = downloadPath.length();
135
136       if( ( 0u == preloadPath.compare( 0u, preloadLength, fileName, 0u, preloadLength ) ) ||
137           ( 0u == downloadPath.compare( 0u, downloadLength, fileName, 0u, downloadLength ) ) )
138       {
139         return true;
140       }
141       return false;
142     }
143     case FontController::LIST_APPLICATION_FONTS:
144     {
145       const std::string& appPath( SETTING_FONT_APP_FONT_PATH );
146       const std::size_t appLength = appPath.length();
147
148       if( 0u == appPath.compare( 0u, appLength, fileName, 0u, appLength ) )
149       {
150         return true;
151       }
152       return false;
153     }
154     default:
155     {
156       DALI_ASSERT_DEBUG( false && "unhandled FontListMode" );
157       return false;
158     }
159   }
160 }
161
162 } // unnamed namespace
163
164 FontController::FontController()
165 {
166   FcInit();
167   FcConfigEnableHome(true);
168 }
169
170 FontController::~FontController()
171 {
172   // clear the font family cache
173   ClearFontFamilyCache();
174
175   // Clear the preferred font list.
176   ClearPreferredFontList();
177 }
178
179 const std::string& FontController::GetFontPath( const StyledFontFamily& styledFontFamily )
180 {
181   DALI_ASSERT_DEBUG( !styledFontFamily.first.empty() && !styledFontFamily.second.empty() && "FontController::GetFontPath(): The font name or the font style is empty. Probably they have not been validated." );
182
183   // lock the mFontFamilyCacheMutex and don't release it until the function finishes.
184   // If we release it then another thread may try to create the same duplicate data.
185   boost::mutex::scoped_lock lock( mFontFamilyCacheMutex );
186
187   StyledFontFamily closestStyledFontFamilyMatch;
188
189   // first check to see if the font has been matched before.
190   closestStyledFontFamilyMatch = GetMatchedFont( styledFontFamily );
191
192   if( closestStyledFontFamilyMatch.first.empty() )
193   {
194     // The font is not in the matches font cache. Use the given one.
195     closestStyledFontFamilyMatch = styledFontFamily;
196   }
197
198   return GetCachedFontPath( closestStyledFontFamilyMatch );
199 }
200
201 void FontController::GetFontList( FontListMode fontListMode, FontList& fontList )
202 {
203   // protect the mFontList from access by multiple threads
204   // this is locked for the entire function, because we don't want two functions
205   // trying to fill the cache with duplicate data.
206   boost::mutex::scoped_lock sharedDatalock( mFontListMutex );
207
208   // if we have already scanned for fonts, return the cached values
209   if ( !mFontSystemList.empty() )
210   {
211     GetCachedFontList( fontListMode, fontList );
212
213     return;
214   }
215
216   // font list needs to be cached
217
218   // font config isn't thread safe
219   boost::mutex::scoped_lock lock( mFontConfigMutex );
220
221   // use font config to get the font set which contains a list of fonts
222   FcFontSet* fontSet = GetFontSet();
223
224   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "number of fonts found: %d\n", fontSet->nfont );
225
226   if( fontSet )
227   {
228     std::string preload_path(SETTING_FONT_PRELOAD_FONT_PATH);
229     std::string download_path(SETTING_FONT_DOWNLOADED_FONT_PATH);
230     std::string application_path(SETTING_FONT_APP_FONT_PATH);
231
232     for( int i = 0u; i < fontSet->nfont; ++i )
233     {
234       FcPattern* fontPattern = fontSet->fonts[i];
235       std::string fileName;
236
237       if( !GetFileName( fontPattern, fileName ) )
238       {
239         continue;  // Has no file name. Jump to the next iteration.
240       }
241
242       // this is checking to make sure the font is in either the normal font path, or download path
243       if( 0u == preload_path.compare( 0u, preload_path.length(), fileName, 0u, preload_path.length() ) ||
244           0u == download_path.compare( 0u, download_path.length(), fileName, 0u, download_path.length() ) ||
245           0u == application_path.compare( 0u, application_path.length(), fileName, 0u, application_path.length() ) )
246       {
247         StyledFontFamily styledFontFamily;
248
249         if( !GetFontFamily( fontPattern, styledFontFamily.first ) )
250         {
251           continue;  // Has no font name. Jump to the next iteration.
252         }
253
254         GetFontStyle( fontPattern, styledFontFamily.second );
255
256         // Add the font to the either the system or application font list
257         AddToFontList( fileName, styledFontFamily );
258       }
259     }
260      // delete the font set
261     FcFontSetDestroy( fontSet );
262   }
263   else
264   {
265      DALI_ASSERT_ALWAYS( false && "No valid fonts found on system." );
266   }
267
268   // return the font list for the specified mode
269   GetCachedFontList( fontListMode, fontList );
270 }
271
272 bool FontController::ValidateFontFamilyName( const StyledFontFamily& styledFontFamily,
273                                              bool& isDefaultSystemFontFamily,
274                                              bool& isDefaultSystemFontStyle,
275                                              StyledFontFamily& closestStyledFontFamilyMatch )
276 {
277   // Initialize the defaults to false as the validation process supposes the given font is correct.
278   isDefaultSystemFontFamily = false;
279   isDefaultSystemFontStyle = false;
280
281   // default the closest Match to empty
282   closestStyledFontFamilyMatch.first.clear();
283   closestStyledFontFamilyMatch.second.clear();
284
285   // lock the mFontFamilyCacheMutex and don't release it until the function finishes.
286   // If we release it then another thread may try to create the same duplicate data.
287   boost::mutex::scoped_lock lock( mFontFamilyCacheMutex );
288
289   StyledFontFamily styledFontFamilyToCheck = styledFontFamily;
290
291   // if the font is blank, then use the default font if it has been cached
292   if( styledFontFamilyToCheck.first.empty() && ( !mDefaultStyledFont.first.empty() ) )
293   {
294     styledFontFamilyToCheck.first = mDefaultStyledFont.first;
295
296     // No font family is given, default system font is used.
297     isDefaultSystemFontFamily = true;
298   }
299
300   if( styledFontFamilyToCheck.second.empty() &&  ( !mDefaultStyledFont.second.empty() ) )
301   {
302     styledFontFamilyToCheck.second = mDefaultStyledFont.second;
303
304     // No font style is given, default system font is used.
305     isDefaultSystemFontStyle = true;
306   }
307
308   // first check to see if the font has been matched before.
309   closestStyledFontFamilyMatch = GetMatchedFont( styledFontFamilyToCheck );
310
311   if( !closestStyledFontFamilyMatch.first.empty() )
312   {
313     // The font has been cached before.
314     return true;
315   }
316
317   // check the cache
318   const std::string& fontFileName = GetCachedFontPath( styledFontFamilyToCheck );
319
320   if( !fontFileName.empty() )
321   {
322     // The font has been cached before.
323
324     closestStyledFontFamilyMatch = styledFontFamilyToCheck;
325
326     return true;
327   }
328
329   DALI_LOG_INFO( gLogFilter, Debug::Verbose,"Failed to find %s %s in cache, querying FontConfig for a match\n", styledFontFamily.first.c_str(), styledFontFamily.second.c_str() );
330
331   // it's not in the cache, find a match using font config and add it to the cache
332   boost::mutex::scoped_lock fcLock( mFontConfigMutex );
333
334   // create the pattern
335   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( styledFontFamilyToCheck );
336
337   FcResult result(FcResultMatch);
338
339   // match the pattern
340   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
341
342   bool validFont = false;
343
344   if( match )
345   {
346     validFont = true;
347
348     CacheFontInfo( match, styledFontFamilyToCheck, closestStyledFontFamilyMatch );
349
350     // destroyed the matched pattern
351     FcPatternDestroy( match );
352   }
353   else
354   {
355     DALI_LOG_ERROR( "FcFontMatch failed for font %s %s\n", styledFontFamilyToCheck.first.c_str(), styledFontFamilyToCheck.second.c_str() );
356   }
357
358   // destroy the pattern
359   FcPatternDestroy( fontFamilyPattern );
360
361   return validFont;
362 }
363
364 const FontController::StyledFontFamily& FontController::GetFontFamilyForChars( const Integration::TextArray& charsRequested )
365 {
366   if( 0u == mPreferredFonts.Count() )
367   {
368     CreatePreferedFontList();
369   }
370
371   // Cycle through the preferred list of fonts on the system for 'Tizen'.
372   for( std::size_t n = 0u; n < mPreferredFonts.Count(); ++n )
373   {
374     const StyledFontFamily& font = *mPreferredFonts[n];
375
376     if( !mPreferredFontsValidated[n] )
377     {
378       // First make sure it is validated and cached so we can access it's character set object
379       bool isDefaultSystemFontFamily = false;
380       bool isDefaultSystemFontStyle = false;
381       StyledFontFamily closestStyledFontFamilyMatch;
382       ValidateFontFamilyName( font,
383                               isDefaultSystemFontFamily,
384                               isDefaultSystemFontStyle,
385                               closestStyledFontFamilyMatch );
386
387       mPreferredFontsValidated[n] = true;
388     }
389
390     const std::string& filePath = GetFontPath( font );
391
392     if( filePath.empty() )
393     {
394       continue;
395     }
396
397     const bool matched = FontFamilySupportsText( font, charsRequested );
398     if( matched )
399     {
400       return font;
401     }
402   }
403
404   // return empty string
405   return NULL_STYLED_FONT_FAMILY;
406 }
407
408 void FontController::CacheFontInfo( FcPattern* pattern, const StyledFontFamily& inputStyledFontFamily, StyledFontFamily& closestStyledFontFamilyMatch )
409 {
410   // Check we can get the following data from the pattern
411
412   if( !GetFontFamily( pattern, closestStyledFontFamilyMatch.first ) )
413   {
414     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "CacheFontInfo failed to get family information from pattern %s %s\n", inputStyledFontFamily.first.c_str(), inputStyledFontFamily.second.c_str() );
415     return;
416   }
417
418   std::string fileName;
419   if( !GetFileName( pattern, fileName ) )
420   {
421     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "CacheFontInfo failed to get file information from pattern %s %s\n", inputStyledFontFamily.first.c_str(), inputStyledFontFamily.second.c_str() );
422     return;
423   }
424
425   FcCharSet* matchedCharSet = NULL;
426   const FcResult retVal = FcPatternGetCharSet( pattern, FC_CHARSET, 0u, &matchedCharSet );
427   if( retVal != FcResultMatch )
428   {
429     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "CacheFontInfo failed to get character set from pattern %s %s\n", inputStyledFontFamily.first.c_str(), inputStyledFontFamily.second.c_str() );
430     return;
431   }
432
433   GetFontStyle( pattern, closestStyledFontFamilyMatch.second );
434
435   // Add the match to the font cache
436   AddCachedFont( closestStyledFontFamilyMatch, fileName, matchedCharSet );
437
438   if( ( !inputStyledFontFamily.first.empty() &&
439         ( inputStyledFontFamily.first != closestStyledFontFamilyMatch.first ) ) &&
440       ( !inputStyledFontFamily.second.empty() &&
441         ( inputStyledFontFamily.second != closestStyledFontFamilyMatch.second ) ) )
442   {
443     // if the font family used to create the pattern was not found in the match then
444     // store it in the MissingFont container
445     AddMatchedFont( inputStyledFontFamily, closestStyledFontFamilyMatch );
446   }
447 }
448
449 bool FontController::AllGlyphsSupported( const StyledFontFamily& styledFontFamily, const Integration::TextArray& text )
450 {
451   // The font has already been validated by the font implementation.
452
453   return FontFamilySupportsText( styledFontFamily, text );
454 }
455
456 void FontController::SetDefaultFontFamily( const StyledFontFamily& styledFontFamily )
457 {
458   // reload font configuration files
459   const bool ok =  FcInitReinitialize();
460   DALI_ASSERT_ALWAYS( ok && "FcInitReinitialize failed");
461
462   CreatePreferedFontList();
463 }
464
465 void FontController::AddCachedFont( const StyledFontFamily& styledFontFamily, const std::string& fontPath, _FcCharSet *characterSet )
466 {
467   FontFamilyLookup::const_iterator iter = mFontFamilyCache.find( styledFontFamily );
468   if( iter == mFontFamilyCache.end() )
469   {
470     // store the path and chacter set
471     FontCacheItem item;
472     item.FontFileName = fontPath;
473     item.FcCharSet = FcCharSetCopy( characterSet );  // increase the ref count on the char set
474     mFontFamilyCache[ styledFontFamily ] = item;
475
476     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Caching font %s %s\n", styledFontFamily.first.c_str(), styledFontFamily.second.c_str() );
477   }
478 }
479
480 void FontController::GetCachedFontList( FontListMode fontListMode, FontList& fontList ) const
481 {
482   // return a list of fonts, for the FontListMode
483   switch( fontListMode )
484   {
485     case LIST_SYSTEM_FONTS:
486     {
487       fontList.insert( fontList.end(), mFontSystemList.begin(), mFontSystemList.end() );
488       return;
489     }
490     case LIST_APPLICATION_FONTS:
491     {
492       fontList.insert( fontList.end(), mFontApplicationList.begin(), mFontApplicationList.end() );
493       return;
494     }
495     case LIST_ALL_FONTS:
496     {
497       // add both system and application fonts together
498       fontList.insert( fontList.end(), mFontSystemList.begin(), mFontSystemList.end() );
499       fontList.insert( fontList.end(), mFontApplicationList.begin(), mFontApplicationList.end() );
500       return;
501     }
502   }
503   DALI_ASSERT_ALWAYS( false && "GetCachedFontList called with invalid value." );
504 }
505
506 const std::string& FontController::GetCachedFontPath( const StyledFontFamily& styledFontFamily ) const
507 {
508   if( !mFontFamilyCache.empty() )
509   {
510     FontFamilyLookup::const_iterator iter = mFontFamilyCache.find( styledFontFamily );
511     if( iter != mFontFamilyCache.end() )
512     {
513       return (*iter).second.FontFileName;
514     }
515   }
516
517   return NULL_FONT_FAMILY_NAME;
518 }
519
520 FcCharSet* FontController::GetCachedFontCharacterSet( const StyledFontFamily& styledFontFamily ) const
521 {
522   if( !mFontFamilyCache.empty() )
523   {
524     FontFamilyLookup::const_iterator iter = mFontFamilyCache.find( styledFontFamily );
525     if( iter != mFontFamilyCache.end() )
526     {
527       return (*iter).second.FcCharSet;
528     }
529   }
530   return NULL;
531 }
532
533 _FcPattern* FontController::CreateFontFamilyPattern( const StyledFontFamily& styledFontFamily )
534 {
535   // create the cached font family lookup pattern
536   // a pattern holds a set of names, each name refers to a property of the font
537   FcPattern* fontFamilyPattern = FcPatternCreate();
538
539   // add a property to the pattern for the font family
540   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( styledFontFamily.first.c_str() ) );
541
542   // add a property to the pattern for the font family
543   FcPatternAddString( fontFamilyPattern, FC_STYLE, reinterpret_cast<const FcChar8*>( styledFontFamily.second.c_str() ) );
544
545   // Add a property of the pattern, to say we want to match TrueType fonts
546   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
547
548   // modify the config, with the mFontFamilyPatterm
549   FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
550
551   // provide default values for unspecified properties in the font pattern
552   // e.g. patterns without a specified style or weight are set to Medium
553   FcDefaultSubstitute( fontFamilyPattern );
554
555   return fontFamilyPattern;
556 }
557
558 bool FontController::IsAControlCharacter( uint32_t character ) const
559 {
560   // UNICODE_CHAR_START is the space character
561   // below it are the control characters that we want to ignore.
562
563   return( ( character < UNICODE_CHAR_START ) ||
564           ( character == UNICODE_CR_LF ) );
565 }
566
567 bool FontController::FontFamilySupportsText( const StyledFontFamily& styledFontFamily, const Integration::TextArray& text )
568 {
569   FcCharSet* charSet = GetCachedFontCharacterSet( styledFontFamily );
570
571   DALI_ASSERT_ALWAYS( charSet && "No cached character set for font family" );
572
573   const size_t textLength = text.Count();
574
575   // quick early exit before accessing font config for text arrays which are just a single control character
576   if( textLength == 1u )
577   {
578     if( IsAControlCharacter( *text.Begin() ) )
579     {
580       return true;
581     }
582   }
583
584   // protect font config
585   boost::mutex::scoped_lock fcLock( mFontConfigMutex );
586
587   for( Integration::TextArray::ConstIterator iter = text.Begin(), endIter = text.End(); iter != endIter; ++iter )
588   {
589     const uint32_t character = (*iter);
590
591     // if it's a control character then don't test it
592     if( IsAControlCharacter( character ) )
593     {
594       continue;
595     }
596
597     // test to see if the character set supports the character
598     if( !FcCharSetHasChar( charSet, character ) )
599     {
600       return false;
601     }
602   }
603   return true;
604 }
605
606 void FontController::ClearFontFamilyCache()
607 {
608   // should be called by the destructor only
609
610   for( FontFamilyLookup::iterator iter = mFontFamilyCache.begin(), enditer = mFontFamilyCache.end(); iter != enditer; ++iter )
611   {
612     FontCacheItem& cacheItem = (*iter).second;
613
614     // this reduces the character sets ref count by 1.
615     FcCharSetDestroy( cacheItem.FcCharSet );
616   }
617
618   mFontFamilyCache.clear();
619 }
620
621 void FontController::AddToFontList( const std::string& fileName, const StyledFontFamily& styledFontFamily )
622 {
623   const bool systemFont = CheckFontInstallPath( LIST_SYSTEM_FONTS, fileName );
624
625   FontList* fontList(NULL);
626
627   if( systemFont )
628   {
629     fontList = &mFontSystemList;
630   }
631   else
632   {
633     fontList = &mFontApplicationList;
634   }
635
636   // check the font family doesn't already exist in the vector, then add it
637   if( fontList->end() == std::find( fontList->begin(), fontList->end(), styledFontFamily ) )
638   {
639     fontList->push_back( styledFontFamily );
640   }
641 }
642
643 _FcFontSet* FontController::GetFontSet() const
644 {
645   // create a new pattern.
646   // a pattern holds a set of names, each name refers to a property of the font
647   FcPattern* pattern = FcPatternCreate();
648
649   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
650   FcObjectSet* objectSet = FcObjectSetCreate();
651
652   // build an object set from a list of property names
653   FcObjectSetAdd( objectSet, FC_FAMILY );
654   FcObjectSetAdd( objectSet, FC_STYLE );
655   FcObjectSetAdd( objectSet, FC_FILE );
656
657   // get a list of fonts
658   // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
659   FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
660
661   // clear up the object set
662   if( objectSet )
663   {
664     FcObjectSetDestroy( objectSet );
665   }
666   // clear up the pattern
667   if( pattern )
668   {
669     FcPatternDestroy( pattern );
670   }
671
672   return fontset;
673 }
674
675 _FcCharSet* FontController::CreateCharacterSet( const Integration::TextArray& charsRequested )
676 {
677   // create the character set object
678   FcCharSet* charSet = FcCharSetCreate();
679
680   bool validCharAdded(false);
681
682   // add valid characters to the character set.
683   for( Integration::TextArray::ConstIterator iter = charsRequested.Begin(), endIter = charsRequested.End(); iter != endIter; ++iter )
684   {
685     const uint32_t character = (*iter);
686
687     // if it's not a control character then add it
688     if( !IsAControlCharacter( character ) )
689     {
690       FcBool ok = FcCharSetAddChar( charSet, character );
691       if( ok )
692       {
693         validCharAdded = true;
694       }
695     }
696   }
697   // if no characters have been added to the character set, then return null
698   if( !validCharAdded )
699   {
700     FcCharSetDestroy(charSet);
701     return NULL;
702   }
703   return charSet;
704 }
705
706 void FontController::AddMatchedFont( const StyledFontFamily& missingStyledFontFamily, StyledFontFamily& closestStyledFontFamilyMatch )
707 {
708   // we store the missing font, and the name of the font that font config found as the closet match
709   mMatchedFontsFound[ missingStyledFontFamily ] = closestStyledFontFamilyMatch;
710 }
711
712 const FontController::StyledFontFamily& FontController::GetMatchedFont( const StyledFontFamily& styledFontFamily ) const
713 {
714   if( mMatchedFontsFound.empty() )
715   {
716     return NULL_STYLED_FONT_FAMILY;
717   }
718
719   MatchedFontLookup::const_iterator iter = mMatchedFontsFound.find( styledFontFamily );
720   if( iter != mMatchedFontsFound.end() )
721   {
722     return iter->second;
723   }
724
725   return NULL_STYLED_FONT_FAMILY;
726 }
727
728 void FontController::CreatePreferedFontList( )
729 {
730   StyledFontFamily tizenFont;
731   tizenFont.first = DEFAULT_FONT_FAMILY_NAME;
732   tizenFont.second = DEFAULT_FONT_STYLE;
733
734   // clear the current list
735   ClearPreferredFontList();
736
737   FcPattern* searchPattern = CreateFontFamilyPattern( tizenFont );
738
739   FcResult result(FcResultMatch);
740
741   // Match the pattern.
742   StyledFontFamily previousFont;
743
744   FcFontSet* fontSet = FcFontSort( NULL /* use default configure */, searchPattern, false /* don't trim */, NULL, &result );
745
746   for( int i = 0u; i < fontSet->nfont; ++i )
747   {
748       // we have already filled in the first entry with the default font
749     FcPattern* pattern = fontSet->fonts[i];
750
751     StyledFontFamily* styledFont = new StyledFontFamily();
752
753     GetFontFamily( pattern, styledFont->first );
754     GetFontStyle( pattern, styledFont->second );
755
756     bool releaseMemory = true;
757     if( *styledFont != previousFont )
758     {
759       mPreferredFonts.PushBack( styledFont );
760       releaseMemory = false;
761     }
762     if( i == 0u )
763     {
764       mDefaultStyledFont = *styledFont;
765     }
766     previousFont = *styledFont;
767
768     if( releaseMemory )
769     {
770        delete styledFont;
771     }
772   }
773
774   // Set all fonts to non validated.
775   mPreferredFontsValidated.Resize( fontSet->nfont, false );
776
777   FcPatternDestroy( searchPattern );
778   FcFontSetDestroy( fontSet );
779 }
780
781 void FontController::ClearPreferredFontList()
782 {
783   for( Vector<StyledFontFamily*>::Iterator it = mPreferredFonts.Begin(), endIt = mPreferredFonts.End(); it != endIt; ++it )
784   {
785     delete *it;
786   }
787   mPreferredFonts.Clear();
788 }
789
790 } // namespace SlpPlatform
791
792 } // namespace Dali
793
794 // Implementation of Dali::Platform::FontController::New()
795 Dali::Platform::FontController* Dali::Platform::FontController::New()
796 {
797   return new Dali::SlpPlatform::FontController();
798 }