Merge "Change SetNativeImageSource() to SetSource()" into devel/master
[platform/core/uifw/dali-adaptor.git] / text / dali / internal / text-abstraction / font-client-plugin-impl.cpp
1 /*
2  * Copyright (c) 2015 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 <dali/internal/text-abstraction/font-client-plugin-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/devel-api/text-abstraction/font-list.h>
23 #include <dali/public-api/common/dali-vector.h>
24 #include <dali/public-api/common/vector-wrapper.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/integration-api/platform-abstraction.h>
27 #include <dali/internal/text-abstraction/font-client-helper.h>
28 #include <adaptor-impl.h>
29
30 // EXTERNAL INCLUDES
31 #include <fontconfig/fontconfig.h>
32
33 namespace
34 {
35
36 #if defined(DEBUG_ENABLED)
37 Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
38 #endif
39
40 /**
41  * Conversion from Fractional26.6 to float
42  */
43 const float FROM_266 = 1.0f / 64.0f;
44
45 const std::string FONT_FORMAT( "TrueType" );
46 const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
47 const int DEFAULT_FONT_WIDTH  = 100; // normal
48 const int DEFAULT_FONT_WEIGHT =  80; // normal
49 const int DEFAULT_FONT_SLANT  =   0; // normal
50
51 const uint32_t ELLIPSIS_CHARACTER = 0x2026;
52
53 const bool FONT_FIXED_SIZE_BITMAP( true );
54
55 // http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
56
57 // ULTRA_CONDENSED 50
58 // EXTRA_CONDENSED 63
59 // CONDENSED       75
60 // SEMI_CONDENSED  87
61 // NORMAL         100
62 // SEMI_EXPANDED  113
63 // EXPANDED       125
64 // EXTRA_EXPANDED 150
65 // ULTRA_EXPANDED 200
66 const int FONT_WIDTH_TYPE_TO_INT[] = { 50, 63, 75, 87, 100, 113, 125, 150, 200 };
67 const unsigned int NUM_FONT_WIDTH_TYPE = sizeof( FONT_WIDTH_TYPE_TO_INT ) / sizeof( int );
68
69 // THIN                        0
70 // ULTRA_LIGHT, EXTRA_LIGHT   40
71 // LIGHT                      50
72 // DEMI_LIGHT, SEMI_LIGHT     55
73 // BOOK                       75
74 // NORMAL, REGULAR            80
75 // MEDIUM                    100
76 // DEMI_BOLD, SEMI_BOLD      180
77 // BOLD                      200
78 // ULTRA_BOLD, EXTRA_BOLD    205
79 // BLACK, HEAVY, EXTRA_BLACK 210
80 const int FONT_WEIGHT_TYPE_TO_INT[] = { 0, 40, 50, 55, 75, 80, 100, 180, 200, 205, 210 };
81 const unsigned int NUM_FONT_WEIGHT_TYPE = sizeof( FONT_WEIGHT_TYPE_TO_INT ) / sizeof( int );
82
83 // NORMAL, ROMAN   0
84 // ITALIC        100
85 // OBLIQUE       110
86 const int FONT_SLANT_TYPE_TO_INT[] = { 0, 100, 110 };
87 const unsigned int NUM_FONT_SLANT_TYPE = sizeof( FONT_SLANT_TYPE_TO_INT ) / sizeof( int );
88
89 } // namespace
90
91 using Dali::Vector;
92
93 namespace Dali
94 {
95
96 namespace TextAbstraction
97 {
98
99 namespace Internal
100 {
101
102 /**
103  * @brief Returns the FontWidth's enum index for the given width value.
104  *
105  * @param[in] width The width value.
106  *
107  * @return The FontWidth's enum index.
108  */
109 FontWidth::Type IntToWidthType( int width )
110 {
111   return static_cast<FontWidth::Type>( ValueToIndex( width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u ) );
112 }
113
114 /**
115  * @brief Returns the FontWeight's enum index for the given weight value.
116  *
117  * @param[in] weight The weight value.
118  *
119  * @return The FontWeight's enum index.
120  */
121 FontWeight::Type IntToWeightType( int weight )
122 {
123   return static_cast<FontWeight::Type>( ValueToIndex( weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u ) );
124 }
125
126 /**
127  * @brief Returns the FontSlant's enum index for the given slant value.
128  *
129  * @param[in] slant The slant value.
130  *
131  * @return The FontSlant's enum index.
132  */
133 FontSlant::Type IntToSlantType( int slant )
134 {
135   return static_cast<FontSlant::Type>( ValueToIndex( slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u ) );
136 }
137
138 FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( const FontDescription& font, FontList* list )
139 : fontDescription( font ),
140   fallbackFonts( list )
141 {
142 }
143
144 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
145                                                                         FontDescriptionId index )
146 : fontDescription( fontDescription ),
147   index( index )
148 {
149 }
150
151 FontClient::Plugin::FontIdCacheItem::FontIdCacheItem( FontDescriptionId validatedFontId,
152                                                       PointSize26Dot6 pointSize,
153                                                       FontId fontId )
154 : validatedFontId( validatedFontId ),
155   pointSize( pointSize ),
156   fontId( fontId )
157 {
158 }
159
160 FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
161                                           const FontPath& path,
162                                           PointSize26Dot6 pointSize,
163                                           FaceIndex face,
164                                           const FontMetrics& metrics )
165 : mFreeTypeFace( ftFace ),
166   mPath( path ),
167   mPointSize( pointSize ),
168   mFaceIndex( face ),
169   mMetrics( metrics ),
170   mFixedWidthPixels( 0.0f ),
171   mFixedHeightPixels( 0.0f ),
172   mIsFixedSizeBitmap( false )
173 {
174 }
175
176 FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
177                                           const FontPath& path,
178                                           PointSize26Dot6 pointSize,
179                                           FaceIndex face,
180                                           const FontMetrics& metrics,
181                                           float fixedWidth,
182                                           float fixedHeight )
183 : mFreeTypeFace( ftFace ),
184   mPath( path ),
185   mPointSize( pointSize ),
186   mFaceIndex( face ),
187   mMetrics( metrics ),
188   mFixedWidthPixels( fixedWidth ),
189   mFixedHeightPixels( fixedHeight ),
190   mIsFixedSizeBitmap( true )
191 {
192 }
193
194 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
195                             unsigned int verticalDpi )
196 : mFreeTypeLibrary( NULL ),
197   mDpiHorizontal( horizontalDpi ),
198   mDpiVertical( verticalDpi ),
199   mDefaultFontDescription(),
200   mSystemFonts(),
201   mDefaultFonts(),
202   mFontCache(),
203   mValidatedFontCache(),
204   mFontDescriptionCache( 1u ),
205   mFontIdCache(),
206   mEllipsisCache(),
207   mDefaultFontDescriptionCached( false )
208 {
209   int error = FT_Init_FreeType( &mFreeTypeLibrary );
210   if( FT_Err_Ok != error )
211   {
212     DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
213   }
214 }
215
216 FontClient::Plugin::~Plugin()
217 {
218   for( std::vector<FallbackCacheItem>::iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
219        it != endIt;
220        ++it )
221   {
222     FallbackCacheItem& item = *it;
223
224     if( item.fallbackFonts )
225     {
226       delete item.fallbackFonts;
227       item.fallbackFonts = NULL;
228     }
229   }
230
231   FT_Done_FreeType( mFreeTypeLibrary );
232 }
233
234 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
235                                  unsigned int verticalDpi )
236 {
237   mDpiHorizontal = horizontalDpi;
238   mDpiVertical = verticalDpi;
239 }
240
241 void FontClient::Plugin::ResetSystemDefaults()
242 {
243   mDefaultFontDescriptionCached = false;
244 }
245
246 void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList )
247 {
248   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::SetFontList family(%s)\n", fontDescription.family.c_str() );
249
250   fontList.clear();
251
252   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
253
254   FcResult result = FcResultMatch;
255
256   // Match the pattern.
257   FcFontSet* fontSet = FcFontSort( NULL /* use default configure */,
258                                    fontFamilyPattern,
259                                    false /* don't trim */,
260                                    NULL,
261                                    &result );
262
263   if( NULL != fontSet )
264   {
265     // Reserve some space to avoid reallocations.
266     fontList.reserve( fontSet->nfont );
267
268     for( int i = 0u; i < fontSet->nfont; ++i )
269     {
270       FcPattern* fontPattern = fontSet->fonts[i];
271
272       FontPath path;
273
274       // Skip fonts with no path
275       if( GetFcString( fontPattern, FC_FILE, path ) )
276       {
277         fontList.push_back( FontDescription() );
278         FontDescription& newFontDescription = fontList.back();
279
280         newFontDescription.path = path;
281
282         int width = 0;
283         int weight = 0;
284         int slant = 0;
285         GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
286         GetFcInt( fontPattern, FC_WIDTH, width );
287         GetFcInt( fontPattern, FC_WEIGHT, weight );
288         GetFcInt( fontPattern, FC_SLANT, slant );
289         newFontDescription.width = IntToWidthType( width );
290         newFontDescription.weight = IntToWeightType( weight );
291         newFontDescription.slant = IntToSlantType( slant );
292       }
293     }
294
295     FcFontSetDestroy( fontSet );
296   }
297
298   FcPatternDestroy( fontFamilyPattern );
299 }
300
301 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
302 {
303   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultFonts mDefaultFonts(%s)\n", ( mDefaultFonts.empty()?"empty":"valid" ) );
304
305   if( mDefaultFonts.empty() )
306   {
307     FontDescription fontDescription;
308     fontDescription.family = DEFAULT_FONT_FAMILY_NAME;  // todo This could be set to the Platform font
309     fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
310     fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
311     fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
312     SetFontList( fontDescription, mDefaultFonts );
313   }
314
315   defaultFonts = mDefaultFonts;
316 }
317
318 void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
319 {
320   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultPlatformFontDescription\n");
321
322   if( !mDefaultFontDescriptionCached )
323   {
324     FcInitReinitialize(); // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
325
326     FcPattern* matchPattern = FcPatternCreate();
327     FcConfigSubstitute(NULL, matchPattern, FcMatchPattern);
328     FcDefaultSubstitute( matchPattern );
329
330     MatchFontDescriptionToPattern( matchPattern, mDefaultFontDescription );
331     FcPatternDestroy( matchPattern );
332
333     mDefaultFontDescriptionCached = true;
334   }
335
336   fontDescription.path   = mDefaultFontDescription.path;
337   fontDescription.family = mDefaultFontDescription.family;
338   fontDescription.width  = mDefaultFontDescription.width;
339   fontDescription.weight = mDefaultFontDescription.weight;
340   fontDescription.slant  = mDefaultFontDescription.slant;
341 }
342
343 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
344 {
345   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetSystemFonts\n");
346
347   if( mSystemFonts.empty() )
348   {
349     InitSystemFonts();
350   }
351
352   systemFonts = mSystemFonts;
353 }
354
355 void FontClient::Plugin::GetDescription( FontId id,
356                                          FontDescription& fontDescription ) const
357 {
358   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
359          endIt = mFontIdCache.end();
360        it != endIt;
361        ++it )
362   {
363     const FontIdCacheItem& item = *it;
364
365     if( item.fontId == id )
366     {
367       fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
368       return;
369     }
370   }
371
372   DALI_LOG_ERROR( "FontClient::Plugin::GetDescription. No description found for the font ID %d\n", id );
373 }
374
375 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
376 {
377   const FontId index = id - 1u;
378
379   if( id > 0u &&
380       index < mFontCache.size() )
381   {
382     return ( *( mFontCache.begin() + index ) ).mPointSize;
383   }
384   else
385   {
386     DALI_LOG_ERROR( "FontClient::Plugin::GetPointSize. Invalid font ID %d\n", id );
387   }
388
389   return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
390 }
391
392 FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList,
393                                                  Character charcode,
394                                                  PointSize26Dot6 requestedSize,
395                                                  bool preferColor )
396 {
397   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFontForCharacter\n");
398
399   FontId fontId(0);
400   bool foundColor(false);
401
402   // Traverse the list of fonts.
403   // Check for each default font if supports the character.
404
405   for( FontList::const_iterator it = fontList.begin(), endIt = fontList.end();
406        it != endIt;
407        ++it )
408   {
409     const FontDescription& description = *it;
410
411     FcPattern* pattern = CreateFontFamilyPattern( description );
412
413     FcResult result = FcResultMatch;
414     FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
415
416     FcCharSet* charSet = NULL;
417     FcPatternGetCharSet( match, FC_CHARSET, 0u, &charSet );
418
419     if( FcCharSetHasChar( charSet, charcode ) )
420     {
421       Vector< PointSize26Dot6 > fixedSizes;
422       GetFixedSizes( description,
423                      fixedSizes );
424
425       const Vector< PointSize26Dot6 >::SizeType count = fixedSizes.Count();
426       if( 0 != count )
427       {
428         // If the font is not scalable, pick the largest size <= requestedSize
429         PointSize26Dot6 size = fixedSizes[0];
430         for( unsigned int i=1; i<count; ++i )
431         {
432           if( fixedSizes[i] <= requestedSize &&
433               fixedSizes[i] > size )
434           {
435             size = fixedSizes[i];
436           }
437         }
438         requestedSize = size;
439       }
440
441       fontId = GetFontId( description,
442                           requestedSize,
443                           0u );
444
445       if( preferColor )
446       {
447         BufferImage bitmap = CreateBitmap( fontId, GetGlyphIndex(fontId,charcode) );
448         if( bitmap &&
449             Pixel::BGRA8888 == bitmap.GetPixelFormat() )
450         {
451           foundColor = true;
452         }
453       }
454
455       // Keep going unless we prefer a different (color) font
456       if( !preferColor || foundColor )
457       {
458         FcPatternDestroy( match );
459         FcPatternDestroy( pattern );
460         break;
461       }
462     }
463
464     FcPatternDestroy( match );
465     FcPatternDestroy( pattern );
466   }
467
468   return fontId;
469 }
470
471 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
472                                             PointSize26Dot6 requestedSize,
473                                             bool preferColor )
474 {
475   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindDefaultFont DefaultFontsList(%s)\n", (mDefaultFonts.empty()?"empty":"created") );
476
477   FontId fontId(0);
478
479   // Create the list of default fonts if it has not been created.
480   if( mDefaultFonts.empty() )
481   {
482     FontDescription fontDescription;
483     fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
484     fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
485     fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
486     fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
487     SetFontList( fontDescription, mDefaultFonts );
488   }
489
490   // Traverse the list of default fonts.
491   // Check for each default font if supports the character.
492   fontId = FindFontForCharacter( mDefaultFonts, charcode, requestedSize, preferColor );
493
494   return fontId;
495 }
496
497 FontId FontClient::Plugin::FindFallbackFont( FontId preferredFont,
498                                              Character charcode,
499                                              PointSize26Dot6 requestedSize,
500                                              bool preferColor )
501 {
502   // The font id to be returned.
503   FontId fontId = 0u;
504
505   FontDescription fontDescription;
506   GetDescription( preferredFont, fontDescription );
507
508   // Check first if the font's description has been queried before.
509   FontList* fontList( NULL );
510
511   if( !FindFallbackFontList( fontDescription, fontList ) )
512   {
513     fontList = new FontList;
514     SetFontList( fontDescription, *fontList );
515
516     // Add the font-list to the cache.
517     mFallbackCache.push_back( FallbackCacheItem(fontDescription, fontList) );
518   }
519
520   if( fontList )
521   {
522     fontId = FindFontForCharacter( *fontList, charcode, requestedSize, preferColor );
523   }
524
525   return fontId;
526 }
527
528 FontId FontClient::Plugin::GetFontId( const FontPath& path,
529                                       PointSize26Dot6 pointSize,
530                                       FaceIndex faceIndex,
531                                       bool cacheDescription )
532 {
533   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId fontPatch:%s\n", path.c_str() );
534
535   FontId id( 0 );
536
537   if( NULL != mFreeTypeLibrary )
538   {
539     FontId foundId(0);
540     if( FindFont( path, pointSize, faceIndex, foundId ) )
541     {
542       id = foundId;
543     }
544     else
545     {
546       id = CreateFont( path, pointSize, faceIndex, cacheDescription );
547     }
548   }
549
550   return id;
551 }
552
553 FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
554                                       PointSize26Dot6 pointSize,
555                                       FaceIndex faceIndex )
556 {
557   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId font family(%s)\n", fontDescription.family.c_str() );
558
559   // This method uses three vectors which caches:
560   // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
561   // * The path to font file names.
562   // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
563
564   // 1) Checks in the cache if the font's description has been validated before.
565   //    If it was it gets an index to the vector with paths to font file names. Otherwise,
566   //    retrieves using font config a path to a font file name which matches with the
567   //    font's description. The path is stored in the cache.
568   //
569   // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
570   //    font file names' exists. If exists, it gets the font id. If it doesn't it calls
571   //    the GetFontId() method with the path to the font file name and the point size to
572   //    get the font id.
573
574   // The font id to be returned.
575   FontId fontId = 0u;
576
577   // Check first if the font's description have been validated before.
578   FontDescriptionId validatedFontId = 0u;
579
580   if( !FindValidatedFont( fontDescription,
581                           validatedFontId ) )
582   {
583     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId Validating Font\n");
584
585     // Use font config to validate the font's description.
586     ValidateFont( fontDescription,
587                   validatedFontId );
588   }
589
590   // Check if exists a pair 'validatedFontId, pointSize' in the cache.
591   if( !FindFont( validatedFontId, pointSize, fontId ) )
592   {
593     // Retrieve the font file name path.
594     const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
595
596     // Retrieve the font id. Do not cache the description as it has been already cached.
597     fontId = GetFontId( description.path,
598                         pointSize,
599                         faceIndex,
600                         false );
601
602     // Cache the pair 'validatedFontId, pointSize' to improve the following queries.
603     mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
604                                              pointSize,
605                                              fontId ) );
606   }
607
608   return fontId;
609 }
610
611 void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
612                                        FontDescriptionId& validatedFontId )
613 {
614   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValidateFont Validating Font family(%s) \n", fontDescription.family.c_str() );
615
616   // Create a font pattern.
617   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
618
619   FontDescription description;
620
621   bool matched = MatchFontDescriptionToPattern( fontFamilyPattern, description );
622   FcPatternDestroy( fontFamilyPattern );
623
624   if( matched )
625   {
626     // Set the index to the vector of paths to font file names.
627     validatedFontId = mFontDescriptionCache.size();
628
629     // Add the path to the cache.
630     mFontDescriptionCache.push_back( description );
631
632     // Cache the index and the font's description.
633     FontDescriptionCacheItem item( description,
634                                    validatedFontId );
635
636     mValidatedFontCache.push_back( item );
637   }
638   else
639   {
640     DALI_LOG_ERROR( "FontClient::Plugin::ValidateFont failed for font %s %d %d %d\n",
641                     fontDescription.family.c_str(),
642                     fontDescription.width,
643                     fontDescription.weight,
644                     fontDescription.slant );
645   }
646
647   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValidateFont validatedFontId(%u) font family(%s)\n", validatedFontId, fontDescription.family.c_str() );
648 }
649
650 void FontClient::Plugin::GetFontMetrics( FontId fontId,
651                                          FontMetrics& metrics,
652                                          int desiredFixedSize )
653 {
654   if( fontId > 0 &&
655       fontId-1 < mFontCache.size() )
656   {
657     const CacheItem& font = mFontCache[fontId-1];
658
659     metrics = font.mMetrics;
660
661     // Adjust the metrics if the fixed-size font should be down-scaled
662     if( font.mIsFixedSizeBitmap &&
663         ( desiredFixedSize > 0 ) )
664     {
665       float scaleFactor = static_cast<float>(desiredFixedSize) / static_cast<float>(font.mFixedHeightPixels);
666
667       metrics.ascender           *= scaleFactor;
668       metrics.descender          *= scaleFactor;
669       metrics.height             *= scaleFactor;
670       metrics.underlinePosition  *= scaleFactor;
671       metrics.underlineThickness *= scaleFactor;
672     }
673   }
674   else
675   {
676     DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
677   }
678 }
679
680 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
681                                               Character charcode )
682 {
683   GlyphIndex index( 0 );
684
685   if( fontId > 0 &&
686       fontId-1 < mFontCache.size() )
687   {
688     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
689
690     index = FT_Get_Char_Index( ftFace, charcode );
691   }
692
693   return index;
694 }
695
696 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
697                                           uint32_t size,
698                                           bool horizontal,
699                                           int desiredFixedSize )
700 {
701   bool success( true );
702
703   for( unsigned int i=0; i<size; ++i )
704   {
705     FontId fontId = array[i].fontId;
706
707     if( fontId > 0 &&
708         fontId-1 < mFontCache.size() )
709     {
710       const CacheItem& font = mFontCache[fontId-1];
711
712       FT_Face ftFace = font.mFreeTypeFace;
713
714 #ifdef FREETYPE_BITMAP_SUPPORT
715       // Check to see if we should be loading a Fixed Size bitmap?
716       if ( font.mIsFixedSizeBitmap )
717       {
718         int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_COLOR );
719         if ( FT_Err_Ok == error )
720         {
721           array[i].width = font.mFixedWidthPixels;
722           array[i].height = font.mFixedHeightPixels;
723           array[i].advance = font.mFixedWidthPixels;
724           array[i].xBearing = 0.0f;
725           array[i].yBearing = font.mFixedHeightPixels;
726
727           // Adjust the metrics if the fixed-size font should be down-scaled
728           if( desiredFixedSize > 0 )
729           {
730             float scaleFactor = static_cast<float>(desiredFixedSize) / static_cast<float>(font.mFixedHeightPixels);
731
732             array[i].width    *= scaleFactor;
733             array[i].height   *= scaleFactor;
734             array[i].advance  *= scaleFactor;
735             array[i].xBearing *= scaleFactor;
736             array[i].yBearing *= scaleFactor;
737
738             array[i].scaleFactor = scaleFactor;
739           }
740         }
741         else
742         {
743           DALI_LOG_ERROR( "FreeType Bitmap Load_Glyph error %d\n", error );
744           success = false;
745         }
746       }
747       else
748 #endif
749       {
750         int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
751
752         if( FT_Err_Ok == error )
753         {
754           array[i].width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
755           array[i].height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
756           if( horizontal )
757           {
758             array[i].xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
759             array[i].yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
760           }
761           else
762           {
763             array[i].xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
764             array[i].yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
765           }
766         }
767         else
768         {
769           success = false;
770         }
771       }
772     }
773     else
774     {
775       success = false;
776     }
777   }
778
779   return success;
780 }
781
782 BufferImage FontClient::Plugin::CreateBitmap( FontId fontId,
783                                               GlyphIndex glyphIndex )
784 {
785   BufferImage bitmap;
786
787   if( fontId > 0 &&
788       fontId-1 < mFontCache.size() )
789   {
790     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
791
792     FT_Error error;
793
794 #ifdef FREETYPE_BITMAP_SUPPORT
795     // Check to see if this is fixed size bitmap
796     if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
797     {
798       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
799     }
800     else
801 #endif
802     {
803       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
804     }
805     if( FT_Err_Ok == error )
806     {
807       FT_Glyph glyph;
808       error = FT_Get_Glyph( ftFace->glyph, &glyph );
809
810       // Convert to bitmap if necessary
811       if ( FT_Err_Ok == error )
812       {
813         if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
814         {
815           error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
816           if ( FT_Err_Ok == error )
817           {
818             FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
819             ConvertBitmap( bitmap, bitmapGlyph->bitmap );
820           }
821           else
822           {
823             DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
824           }
825         }
826         else
827         {
828           ConvertBitmap( bitmap, ftFace->glyph->bitmap );
829         }
830
831         // Created FT_Glyph object must be released with FT_Done_Glyph
832         FT_Done_Glyph( glyph );
833       }
834     }
835     else
836     {
837       DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
838     }
839   }
840
841   return bitmap;
842 }
843
844 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 pointSize )
845 {
846   // First look into the cache if there is an ellipsis glyph for the requested point size.
847   for( Vector<EllipsisItem>::ConstIterator it = mEllipsisCache.Begin(),
848          endIt = mEllipsisCache.End();
849        it != endIt;
850        ++it )
851   {
852     const EllipsisItem& item = *it;
853
854     if( fabsf( item.size - pointSize ) < Math::MACHINE_EPSILON_1000 )
855     {
856       // Use the glyph in the cache.
857       return item.glyph;
858     }
859   }
860
861   // No glyph has been found. Create one.
862   mEllipsisCache.PushBack( EllipsisItem() );
863   EllipsisItem& item = *( mEllipsisCache.End() - 1u );
864
865   item.size = pointSize;
866
867   // Find a font for the ellipsis glyph.
868   item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
869                                        pointSize,
870                                        false );
871
872   // Set the character index to access the glyph inside the font.
873   item.glyph.index = FT_Get_Char_Index( mFontCache[item.glyph.fontId-1].mFreeTypeFace,
874                                         ELLIPSIS_CHARACTER );
875
876   GetGlyphMetrics( &item.glyph, 1u, true, 0 );
877
878   return item.glyph;
879 }
880
881 void FontClient::Plugin::InitSystemFonts()
882 {
883   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts \n");
884
885   FcFontSet* fontSet = GetFcFontSet();
886
887   if( fontSet )
888   {
889     // Reserve some space to avoid reallocations.
890     mSystemFonts.reserve( fontSet->nfont );
891
892     for( int i = 0u; i < fontSet->nfont; ++i )
893     {
894       FcPattern* fontPattern = fontSet->fonts[i];
895
896       FontPath path;
897
898       // Skip fonts with no path
899       if( GetFcString( fontPattern, FC_FILE, path ) )
900       {
901         mSystemFonts.push_back( FontDescription() );
902         FontDescription& fontDescription = mSystemFonts.back();
903
904         fontDescription.path = path;
905
906         int width = 0;
907         int weight = 0;
908         int slant = 0;
909         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
910         GetFcInt( fontPattern, FC_WIDTH, width );
911         GetFcInt( fontPattern, FC_WEIGHT, weight );
912         GetFcInt( fontPattern, FC_SLANT, slant );
913         fontDescription.width = IntToWidthType( width );
914         fontDescription.weight = IntToWeightType( weight );
915         fontDescription.slant = IntToSlantType( slant );
916         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts font family(%s)\n", fontDescription.family.c_str() );
917
918       }
919     }
920
921     FcFontSetDestroy( fontSet );
922   }
923 }
924
925 bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription )
926 {
927   FcResult result = FcResultMatch;
928   FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
929
930   bool ret = false;
931
932   if( match )
933   {
934     int width = 0;
935     int weight = 0;
936     int slant = 0;
937     GetFcString( match, FC_FILE, fontDescription.path );
938     GetFcString( match, FC_FAMILY, fontDescription.family );
939     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::MatchFontDescriptionToPattern matched:%s \n", fontDescription.family.c_str());
940     GetFcInt( match, FC_WIDTH, width );
941     GetFcInt( match, FC_WEIGHT, weight );
942     GetFcInt( match, FC_SLANT, slant );
943     fontDescription.width = IntToWidthType( width );
944     fontDescription.weight = IntToWeightType( weight );
945     fontDescription.slant = IntToSlantType( slant );
946     // destroyed the matched pattern
947     FcPatternDestroy( match );
948     ret = true;
949   }
950   return ret;
951 }
952
953
954 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription )
955 {
956   // create the cached font family lookup pattern
957   // a pattern holds a set of names, each name refers to a property of the font
958   FcPattern* fontFamilyPattern = FcPatternCreate();
959
960   // add a property to the pattern for the font family
961   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
962
963   FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, FONT_WIDTH_TYPE_TO_INT[fontDescription.width] );
964   FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight] );
965   FcPatternAddInteger( fontFamilyPattern, FC_SLANT, FONT_SLANT_TYPE_TO_INT[fontDescription.slant] );
966
967   // Add a property of the pattern, to say we want to match TrueType fonts
968   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
969
970   // modify the config, with the mFontFamilyPatterm
971   FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
972
973   // provide default values for unspecified properties in the font pattern
974   // e.g. patterns without a specified style or weight are set to Medium
975   FcDefaultSubstitute( fontFamilyPattern );
976
977   return fontFamilyPattern;
978 }
979
980 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
981 {
982   // create a new pattern.
983   // a pattern holds a set of names, each name refers to a property of the font
984   FcPattern* pattern = FcPatternCreate();
985
986   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
987   FcObjectSet* objectSet = FcObjectSetCreate();
988
989   // build an object set from a list of property names
990   FcObjectSetAdd( objectSet, FC_FILE );
991   FcObjectSetAdd( objectSet, FC_FAMILY );
992   FcObjectSetAdd( objectSet, FC_WIDTH );
993   FcObjectSetAdd( objectSet, FC_WEIGHT );
994   FcObjectSetAdd( objectSet, FC_SLANT );
995
996   // get a list of fonts
997   // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
998   FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
999
1000   // clear up the object set
1001   if( objectSet )
1002   {
1003     FcObjectSetDestroy( objectSet );
1004   }
1005   // clear up the pattern
1006   if( pattern )
1007   {
1008     FcPatternDestroy( pattern );
1009   }
1010
1011   return fontset;
1012 }
1013
1014 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1015                                       const char* const n,
1016                                       std::string& string )
1017 {
1018   FcChar8* file = NULL;
1019   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1020
1021   if( FcResultMatch == retVal )
1022   {
1023     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1024     string.assign( reinterpret_cast<const char*>( file ) );
1025
1026     return true;
1027   }
1028
1029   return false;
1030 }
1031
1032 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
1033 {
1034   const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
1035
1036   if( FcResultMatch == retVal )
1037   {
1038     return true;
1039   }
1040
1041   return false;
1042 }
1043
1044 FontId FontClient::Plugin::CreateFont( const FontPath& path,
1045                                        PointSize26Dot6 pointSize,
1046                                        FaceIndex faceIndex,
1047                                        bool cacheDescription )
1048 {
1049   FontId id( 0 );
1050
1051   // Create & cache new font face
1052   FT_Face ftFace;
1053   int error = FT_New_Face( mFreeTypeLibrary,
1054                            path.c_str(),
1055                            0,
1056                            &ftFace );
1057
1058   if( FT_Err_Ok == error )
1059   {
1060     // Check to see if the font contains fixed sizes?
1061     if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1062     {
1063       // Ensure this size is available
1064       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1065       {
1066         if ( static_cast<FT_Pos>(pointSize) == ftFace->available_sizes[ i ].size )
1067         {
1068           // Tell Freetype to use this size
1069           error = FT_Select_Size( ftFace, i );
1070           if ( FT_Err_Ok != error )
1071           {
1072             DALI_LOG_ERROR( "FreeType Select_Size error: %d\n", error );
1073           }
1074           else
1075           {
1076             float fixedWidth  = static_cast< float >( ftFace->available_sizes[ i ].width );
1077             float fixedHeight = static_cast< float >( ftFace->available_sizes[ i ].height );
1078
1079             // Indicate that the font is a fixed sized bitmap
1080             FontMetrics metrics( fixedHeight, // The ascender in pixels.
1081                                  0.0f,
1082                                  fixedHeight, // The height in pixels.
1083                                  0.0f,
1084                                  0.0f );
1085
1086             mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics, fixedWidth, fixedHeight ) );
1087             id = mFontCache.size();
1088
1089             if( cacheDescription )
1090             {
1091               CacheFontPath( ftFace, id, pointSize, path );
1092             }
1093             return id;
1094           }
1095         }
1096       }
1097
1098       // Can't find this size
1099       std::stringstream sizes;
1100       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1101       {
1102         if ( i )
1103         {
1104           sizes << ", ";
1105         }
1106         sizes << ftFace->available_sizes[ i ].size;
1107       }
1108       DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n",
1109                        path.c_str(), pointSize, sizes.str().c_str() );
1110     }
1111     else
1112     {
1113       error = FT_Set_Char_Size( ftFace,
1114                                 0,
1115                                 pointSize,
1116                                 mDpiHorizontal,
1117                                 mDpiVertical );
1118
1119       if( FT_Err_Ok == error )
1120       {
1121
1122         FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1123
1124         FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
1125                              static_cast< float >( ftMetrics.descender ) * FROM_266,
1126                              static_cast< float >( ftMetrics.height    ) * FROM_266,
1127                              static_cast< float >( ftFace->underline_position ) * FROM_266,
1128                              static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1129
1130         mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics ) );
1131         id = mFontCache.size();
1132
1133         if( cacheDescription )
1134         {
1135           CacheFontPath( ftFace, id, pointSize, path );
1136         }
1137       }
1138       else
1139       {
1140         DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, pointSize );
1141       }
1142     }
1143   }
1144   else
1145   {
1146     DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
1147   }
1148
1149   return id;
1150 }
1151
1152 void FontClient::Plugin::ConvertBitmap( BufferImage& destBitmap,
1153                                         FT_Bitmap srcBitmap )
1154 {
1155   if( srcBitmap.width*srcBitmap.rows > 0 )
1156   {
1157     switch( srcBitmap.pixel_mode )
1158     {
1159       case FT_PIXEL_MODE_GRAY:
1160       {
1161         if( srcBitmap.pitch == static_cast< int >( srcBitmap.width ) )
1162         {
1163           destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
1164
1165           PixelBuffer* destBuffer = destBitmap.GetBuffer();
1166           if( destBuffer )
1167           {
1168             memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
1169           }
1170           else
1171           {
1172             DALI_LOG_ERROR( "GetBuffer returns null\n" );
1173           }
1174         }
1175         break;
1176       }
1177
1178 #ifdef FREETYPE_BITMAP_SUPPORT
1179       case FT_PIXEL_MODE_BGRA:
1180       {
1181         if ( srcBitmap.pitch == static_cast< int >( srcBitmap.width << 2 ) )
1182         {
1183           destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::BGRA8888 );
1184
1185           PixelBuffer* destBuffer = destBitmap.GetBuffer();
1186           if( destBuffer )
1187           {
1188             memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows*4 );
1189           }
1190           else
1191           {
1192             DALI_LOG_ERROR( "GetBuffer returns null\n" );
1193           }
1194         }
1195         break;
1196       }
1197 #endif
1198       default:
1199       {
1200         DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" );
1201         break;
1202       }
1203     }
1204   }
1205 }
1206
1207 bool FontClient::Plugin::FindFont( const FontPath& path,
1208                                    PointSize26Dot6 pointSize,
1209                                    FaceIndex faceIndex,
1210                                    FontId& fontId ) const
1211 {
1212   fontId = 0u;
1213   for( std::vector<CacheItem>::const_iterator it = mFontCache.begin(),
1214          endIt = mFontCache.end();
1215        it != endIt;
1216        ++it, ++fontId )
1217   {
1218     const CacheItem& cacheItem = *it;
1219
1220     if( cacheItem.mPointSize == pointSize &&
1221         cacheItem.mFaceIndex == faceIndex &&
1222         cacheItem.mPath == path )
1223     {
1224       ++fontId;
1225       return true;
1226     }
1227   }
1228
1229   return false;
1230 }
1231
1232 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1233                                             FontDescriptionId& validatedFontId )
1234 {
1235   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont fontDescription family(%s)\n", fontDescription.family.c_str() );
1236
1237   validatedFontId = 0u;
1238
1239   for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
1240          endIt = mValidatedFontCache.end();
1241        it != endIt;
1242        ++it )
1243   {
1244     const FontDescriptionCacheItem& item = *it;
1245
1246     if( !fontDescription.family.empty() &&
1247         ( fontDescription.family == item.fontDescription.family ) &&
1248         ( fontDescription.width == item.fontDescription.width ) &&
1249         ( fontDescription.weight == item.fontDescription.weight ) &&
1250         ( fontDescription.slant == item.fontDescription.slant ) )
1251     {
1252       validatedFontId = item.index;
1253
1254       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont validated font family(%s) font id (%u) \n", fontDescription.family.c_str(), validatedFontId );
1255
1256       return true;
1257     }
1258   }
1259
1260   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont NOT VALIDATED return false\n" );
1261
1262   return false;
1263 }
1264
1265 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
1266                                                FontList*& fontList )
1267 {
1268   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList fontDescription family(%s)\n", fontDescription.family.c_str() );
1269
1270   fontList = NULL;
1271
1272   for( std::vector<FallbackCacheItem>::const_iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
1273        it != endIt;
1274        ++it )
1275   {
1276     const FallbackCacheItem& item = *it;
1277
1278     if( !fontDescription.family.empty() &&
1279         ( fontDescription.family == item.fontDescription.family ) &&
1280         ( fontDescription.width == item.fontDescription.width ) &&
1281         ( fontDescription.weight == item.fontDescription.weight ) &&
1282         ( fontDescription.slant == item.fontDescription.slant ) )
1283     {
1284       fontList = item.fallbackFonts;
1285
1286       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList font family(%s) font-list (%p) \n", fontDescription.family.c_str(), fontList );
1287
1288       return true;
1289     }
1290   }
1291
1292   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList NOT FOUND return false\n" );
1293
1294   return false;
1295 }
1296
1297 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1298                                    PointSize26Dot6 pointSize,
1299                                    FontId& fontId )
1300 {
1301   fontId = 0u;
1302
1303   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
1304          endIt = mFontIdCache.end();
1305        it != endIt;
1306        ++it )
1307   {
1308     const FontIdCacheItem& item = *it;
1309
1310     if( ( validatedFontId == item.validatedFontId ) &&
1311         ( pointSize == item.pointSize ) )
1312     {
1313       fontId = item.fontId;
1314       return true;
1315     }
1316   }
1317
1318   return false;
1319 }
1320
1321 bool FontClient::Plugin::IsScalable( const FontPath& path )
1322 {
1323   FT_Face ftFace;
1324   int error = FT_New_Face( mFreeTypeLibrary,
1325                            path.c_str(),
1326                            0,
1327                            &ftFace );
1328   if( FT_Err_Ok != error )
1329   {
1330     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1331   }
1332   return ( ftFace->num_fixed_sizes == 0 );
1333 }
1334
1335 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1336 {
1337   // Create a font pattern.
1338   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1339
1340   FcResult result = FcResultMatch;
1341
1342   // match the pattern
1343   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1344   bool isScalable = true;
1345
1346   if( match )
1347   {
1348     // Get the path to the font file name.
1349     FontPath path;
1350     GetFcString( match, FC_FILE, path );
1351     isScalable = IsScalable( path );
1352   }
1353   else
1354   {
1355     DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1356                     fontDescription.family.c_str(),
1357                     fontDescription.width,
1358                     fontDescription.weight,
1359                     fontDescription.slant );
1360   }
1361   FcPatternDestroy( fontFamilyPattern );
1362   FcPatternDestroy( match );
1363   return isScalable;
1364 }
1365
1366 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1367 {
1368   // Empty the caller container
1369   sizes.Clear();
1370
1371   FT_Face ftFace;
1372   int error = FT_New_Face( mFreeTypeLibrary,
1373                            path.c_str(),
1374                            0,
1375                            &ftFace );
1376   if( FT_Err_Ok != error )
1377   {
1378     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1379   }
1380
1381   // Fetch the number of fixed sizes available
1382   if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1383   {
1384     for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1385     {
1386       sizes.PushBack( ftFace->available_sizes[ i ].size );
1387     }
1388   }
1389 }
1390
1391 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1392                                         Vector< PointSize26Dot6 >& sizes )
1393 {
1394   // Create a font pattern.
1395   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1396
1397   FcResult result = FcResultMatch;
1398
1399   // match the pattern
1400   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1401
1402   if( match )
1403   {
1404     // Get the path to the font file name.
1405     FontPath path;
1406     GetFcString( match, FC_FILE, path );
1407     GetFixedSizes( path, sizes );
1408   }
1409   else
1410   {
1411     DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1412                     fontDescription.family.c_str(),
1413                     fontDescription.width,
1414                     fontDescription.weight,
1415                     fontDescription.slant );
1416   }
1417   FcPatternDestroy( match );
1418   FcPatternDestroy( fontFamilyPattern );
1419 }
1420
1421 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 pointSize,  const FontPath& path )
1422 {
1423   FontDescription description;
1424   description.path = path;
1425   description.family = FontFamily( ftFace->family_name );
1426   description.weight = FontWeight::NORMAL;
1427   description.width = FontWidth::NORMAL;
1428   description.slant = FontSlant::NORMAL;
1429
1430   // Note FreeType doesn't give too much info to build a proper font style.
1431   if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1432   {
1433     description.slant = FontSlant::ITALIC;
1434   }
1435   if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1436   {
1437     description.weight = FontWeight::BOLD;
1438   }
1439
1440   FontDescriptionId validatedFontId = 0u;
1441   if( !FindValidatedFont( description,
1442                           validatedFontId ) )
1443   {
1444     // Set the index to the vector of paths to font file names.
1445     validatedFontId = mFontDescriptionCache.size();
1446
1447     // Add the path to the cache.
1448     mFontDescriptionCache.push_back( description );
1449
1450     // Cache the index and the font's description.
1451     FontDescriptionCacheItem item( description,
1452                                    validatedFontId );
1453
1454     mValidatedFontCache.push_back( item );
1455
1456     // Cache the pair 'validatedFontId, pointSize' to improve the following queries.
1457     mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
1458                                              pointSize,
1459                                              id ) );
1460   }
1461 }
1462
1463 } // namespace Internal
1464
1465 } // namespace TextAbstraction
1466
1467 } // namespace Dali