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