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