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