Merge branch 'devel/master (1.1.16)' 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   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 maxFixedSize )
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         ( maxFixedSize > 0 ) &&
664         ( font.mFixedHeightPixels > maxFixedSize ) )
665     {
666       float scaleFactor = static_cast<float>(maxFixedSize) / static_cast<float>(font.mFixedHeightPixels);
667
668       metrics.ascender           *= scaleFactor;
669       metrics.descender          *= scaleFactor;
670       metrics.height             *= scaleFactor;
671       metrics.underlinePosition  *= scaleFactor;
672       metrics.underlineThickness *= scaleFactor;
673     }
674   }
675   else
676   {
677     DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
678   }
679 }
680
681 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
682                                               Character charcode )
683 {
684   GlyphIndex index( 0 );
685
686   if( fontId > 0 &&
687       fontId-1 < mFontCache.size() )
688   {
689     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
690
691     index = FT_Get_Char_Index( ftFace, charcode );
692   }
693
694   return index;
695 }
696
697 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
698                                           uint32_t size,
699                                           bool horizontal,
700                                           int maxFixedSize )
701 {
702   bool success( true );
703
704   for( unsigned int i=0; i<size; ++i )
705   {
706     FontId fontId = array[i].fontId;
707
708     if( fontId > 0 &&
709         fontId-1 < mFontCache.size() )
710     {
711       const CacheItem& font = mFontCache[fontId-1];
712
713       FT_Face ftFace = font.mFreeTypeFace;
714
715 #ifdef FREETYPE_BITMAP_SUPPORT
716       // Check to see if we should be loading a Fixed Size bitmap?
717       if ( font.mIsFixedSizeBitmap )
718       {
719         int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_COLOR );
720         if ( FT_Err_Ok == error )
721         {
722           array[i].width = font.mFixedWidthPixels;
723           array[i].height = font.mFixedHeightPixels;
724           array[i].advance = font.mFixedWidthPixels;
725           array[i].xBearing = 0.0f;
726           array[i].yBearing = font.mFixedHeightPixels;
727
728           // Adjust the metrics if the fixed-size font should be down-scaled
729           if( ( maxFixedSize > 0 ) &&
730               ( font.mFixedHeightPixels > maxFixedSize ) )
731           {
732             float scaleFactor = static_cast<float>(maxFixedSize) / static_cast<float>(font.mFixedHeightPixels);
733
734             array[i].width    *= scaleFactor;
735             array[i].height   *= scaleFactor;
736             array[i].advance  *= scaleFactor;
737             array[i].xBearing *= scaleFactor;
738             array[i].yBearing *= scaleFactor;
739
740             array[i].scaleFactor = scaleFactor;
741           }
742         }
743         else
744         {
745           DALI_LOG_ERROR( "FreeType Bitmap Load_Glyph error %d\n", error );
746           success = false;
747         }
748       }
749       else
750 #endif
751       {
752         int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
753
754         if( FT_Err_Ok == error )
755         {
756           array[i].width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
757           array[i].height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
758           if( horizontal )
759           {
760             array[i].xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
761             array[i].yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
762           }
763           else
764           {
765             array[i].xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
766             array[i].yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
767           }
768         }
769         else
770         {
771           success = false;
772         }
773       }
774     }
775     else
776     {
777       success = false;
778     }
779   }
780
781   return success;
782 }
783
784 BufferImage FontClient::Plugin::CreateBitmap( FontId fontId,
785                                               GlyphIndex glyphIndex )
786 {
787   BufferImage bitmap;
788
789   if( fontId > 0 &&
790       fontId-1 < mFontCache.size() )
791   {
792     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
793
794     FT_Error error;
795
796 #ifdef FREETYPE_BITMAP_SUPPORT
797     // Check to see if this is fixed size bitmap
798     if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
799     {
800       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
801     }
802     else
803 #endif
804     {
805       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
806     }
807     if( FT_Err_Ok == error )
808     {
809       FT_Glyph glyph;
810       error = FT_Get_Glyph( ftFace->glyph, &glyph );
811
812       // Convert to bitmap if necessary
813       if ( FT_Err_Ok == error )
814       {
815         if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
816         {
817           error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
818           if ( FT_Err_Ok == error )
819           {
820             FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
821             ConvertBitmap( bitmap, bitmapGlyph->bitmap );
822           }
823           else
824           {
825             DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
826           }
827         }
828         else
829         {
830           ConvertBitmap( bitmap, ftFace->glyph->bitmap );
831         }
832
833         // Created FT_Glyph object must be released with FT_Done_Glyph
834         FT_Done_Glyph( glyph );
835       }
836     }
837     else
838     {
839       DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
840     }
841   }
842
843   return bitmap;
844 }
845
846 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 pointSize )
847 {
848   // First look into the cache if there is an ellipsis glyph for the requested point size.
849   for( Vector<EllipsisItem>::ConstIterator it = mEllipsisCache.Begin(),
850          endIt = mEllipsisCache.End();
851        it != endIt;
852        ++it )
853   {
854     const EllipsisItem& item = *it;
855
856     if( fabsf( item.size - pointSize ) < Math::MACHINE_EPSILON_1000 )
857     {
858       // Use the glyph in the cache.
859       return item.glyph;
860     }
861   }
862
863   // No glyph has been found. Create one.
864   mEllipsisCache.PushBack( EllipsisItem() );
865   EllipsisItem& item = *( mEllipsisCache.End() - 1u );
866
867   item.size = pointSize;
868
869   // Find a font for the ellipsis glyph.
870   item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
871                                        pointSize,
872                                        false );
873
874   // Set the character index to access the glyph inside the font.
875   item.glyph.index = FT_Get_Char_Index( mFontCache[item.glyph.fontId-1].mFreeTypeFace,
876                                         ELLIPSIS_CHARACTER );
877
878   GetGlyphMetrics( &item.glyph, 1u, true, 0 );
879
880   return item.glyph;
881 }
882
883 void FontClient::Plugin::InitSystemFonts()
884 {
885   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts \n");
886
887   FcFontSet* fontSet = GetFcFontSet();
888
889   if( fontSet )
890   {
891     // Reserve some space to avoid reallocations.
892     mSystemFonts.reserve( fontSet->nfont );
893
894     for( int i = 0u; i < fontSet->nfont; ++i )
895     {
896       FcPattern* fontPattern = fontSet->fonts[i];
897
898       FontPath path;
899
900       // Skip fonts with no path
901       if( GetFcString( fontPattern, FC_FILE, path ) )
902       {
903         mSystemFonts.push_back( FontDescription() );
904         FontDescription& fontDescription = mSystemFonts.back();
905
906         fontDescription.path = path;
907
908         int width = 0;
909         int weight = 0;
910         int slant = 0;
911         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
912         GetFcInt( fontPattern, FC_WIDTH, width );
913         GetFcInt( fontPattern, FC_WEIGHT, weight );
914         GetFcInt( fontPattern, FC_SLANT, slant );
915         fontDescription.width = IntToWidthType( width );
916         fontDescription.weight = IntToWeightType( weight );
917         fontDescription.slant = IntToSlantType( slant );
918         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts font family(%s)\n", fontDescription.family.c_str() );
919
920       }
921     }
922
923     FcFontSetDestroy( fontSet );
924   }
925 }
926
927 bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription )
928 {
929   FcResult result = FcResultMatch;
930   FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
931
932   bool ret = false;
933
934   if( match )
935   {
936     int width = 0;
937     int weight = 0;
938     int slant = 0;
939     GetFcString( match, FC_FILE, fontDescription.path );
940     GetFcString( match, FC_FAMILY, fontDescription.family );
941     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::MatchFontDescriptionToPattern matched:%s \n", fontDescription.family.c_str());
942     GetFcInt( match, FC_WIDTH, width );
943     GetFcInt( match, FC_WEIGHT, weight );
944     GetFcInt( match, FC_SLANT, slant );
945     fontDescription.width = IntToWidthType( width );
946     fontDescription.weight = IntToWeightType( weight );
947     fontDescription.slant = IntToSlantType( slant );
948     // destroyed the matched pattern
949     FcPatternDestroy( match );
950     ret = true;
951   }
952   return ret;
953 }
954
955
956 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription )
957 {
958   // create the cached font family lookup pattern
959   // a pattern holds a set of names, each name refers to a property of the font
960   FcPattern* fontFamilyPattern = FcPatternCreate();
961
962   // add a property to the pattern for the font family
963   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
964
965   FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, FONT_WIDTH_TYPE_TO_INT[fontDescription.width] );
966   FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight] );
967   FcPatternAddInteger( fontFamilyPattern, FC_SLANT, FONT_SLANT_TYPE_TO_INT[fontDescription.slant] );
968
969   // Add a property of the pattern, to say we want to match TrueType fonts
970   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
971
972   // modify the config, with the mFontFamilyPatterm
973   FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
974
975   // provide default values for unspecified properties in the font pattern
976   // e.g. patterns without a specified style or weight are set to Medium
977   FcDefaultSubstitute( fontFamilyPattern );
978
979   return fontFamilyPattern;
980 }
981
982 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
983 {
984   // create a new pattern.
985   // a pattern holds a set of names, each name refers to a property of the font
986   FcPattern* pattern = FcPatternCreate();
987
988   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
989   FcObjectSet* objectSet = FcObjectSetCreate();
990
991   // build an object set from a list of property names
992   FcObjectSetAdd( objectSet, FC_FILE );
993   FcObjectSetAdd( objectSet, FC_FAMILY );
994   FcObjectSetAdd( objectSet, FC_WIDTH );
995   FcObjectSetAdd( objectSet, FC_WEIGHT );
996   FcObjectSetAdd( objectSet, FC_SLANT );
997
998   // get a list of fonts
999   // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
1000   FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
1001
1002   // clear up the object set
1003   if( objectSet )
1004   {
1005     FcObjectSetDestroy( objectSet );
1006   }
1007   // clear up the pattern
1008   if( pattern )
1009   {
1010     FcPatternDestroy( pattern );
1011   }
1012
1013   return fontset;
1014 }
1015
1016 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1017                                       const char* const n,
1018                                       std::string& string )
1019 {
1020   FcChar8* file = NULL;
1021   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1022
1023   if( FcResultMatch == retVal )
1024   {
1025     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1026     string.assign( reinterpret_cast<const char*>( file ) );
1027
1028     return true;
1029   }
1030
1031   return false;
1032 }
1033
1034 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
1035 {
1036   const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
1037
1038   if( FcResultMatch == retVal )
1039   {
1040     return true;
1041   }
1042
1043   return false;
1044 }
1045
1046 FontId FontClient::Plugin::CreateFont( const FontPath& path,
1047                                        PointSize26Dot6 pointSize,
1048                                        FaceIndex faceIndex,
1049                                        bool cacheDescription )
1050 {
1051   FontId id( 0 );
1052
1053   // Create & cache new font face
1054   FT_Face ftFace;
1055   int error = FT_New_Face( mFreeTypeLibrary,
1056                            path.c_str(),
1057                            0,
1058                            &ftFace );
1059
1060   if( FT_Err_Ok == error )
1061   {
1062     // Check to see if the font contains fixed sizes?
1063     if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1064     {
1065       // Ensure this size is available
1066       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1067       {
1068         if ( static_cast<FT_Pos>(pointSize) == ftFace->available_sizes[ i ].size )
1069         {
1070           // Tell Freetype to use this size
1071           error = FT_Select_Size( ftFace, i );
1072           if ( FT_Err_Ok != error )
1073           {
1074             DALI_LOG_ERROR( "FreeType Select_Size error: %d\n", error );
1075           }
1076           else
1077           {
1078             float fixedWidth  = static_cast< float >( ftFace->available_sizes[ i ].width );
1079             float fixedHeight = static_cast< float >( ftFace->available_sizes[ i ].height );
1080
1081             // Indicate that the font is a fixed sized bitmap
1082             FontMetrics metrics( fixedHeight, // The ascender in pixels.
1083                                  0.0f,
1084                                  fixedHeight, // The height in pixels.
1085                                  0.0f,
1086                                  0.0f );
1087
1088             mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics, fixedWidth, fixedHeight ) );
1089             id = mFontCache.size();
1090
1091             if( cacheDescription )
1092             {
1093               FontDescription description;
1094               description.path = path;
1095               description.family = FontFamily( ftFace->family_name );
1096
1097               // Note FreeType doesn't give too much info to build a proper font style.
1098               if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1099               {
1100                 description.slant = FontSlant::ITALIC;
1101               }
1102               if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1103               {
1104                 description.weight = FontWeight::BOLD;
1105               }
1106
1107               mFontDescriptionCache.push_back( description );
1108             }
1109             return id;
1110           }
1111         }
1112       }
1113
1114       // Can't find this size
1115       std::stringstream sizes;
1116       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1117       {
1118         if ( i )
1119         {
1120           sizes << ", ";
1121         }
1122         sizes << ftFace->available_sizes[ i ].size;
1123       }
1124       DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n",
1125                        path.c_str(), pointSize, sizes.str().c_str() );
1126     }
1127     else
1128     {
1129       error = FT_Set_Char_Size( ftFace,
1130                               0,
1131                               pointSize,
1132                               mDpiHorizontal,
1133                               mDpiVertical );
1134
1135       if( FT_Err_Ok == error )
1136       {
1137
1138         FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1139
1140         FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
1141                              static_cast< float >( ftMetrics.descender ) * FROM_266,
1142                              static_cast< float >( ftMetrics.height    ) * FROM_266,
1143                              static_cast< float >( ftFace->underline_position ) * FROM_266,
1144                              static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1145
1146         mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics ) );
1147         id = mFontCache.size();
1148
1149         if( cacheDescription )
1150         {
1151           FontDescription description;
1152           description.path = path;
1153           description.family = FontFamily( ftFace->family_name );
1154
1155           // Note FreeType doesn't give too much info to build a proper font style.
1156           if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1157           {
1158             description.slant = FontSlant::ITALIC;
1159           }
1160           if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1161           {
1162             description.weight = FontWeight::BOLD;
1163           }
1164
1165           mFontDescriptionCache.push_back( description );
1166         }
1167       }
1168       else
1169       {
1170         DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, pointSize );
1171       }
1172     }
1173   }
1174   else
1175   {
1176     DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
1177   }
1178
1179   return id;
1180 }
1181
1182 void FontClient::Plugin::ConvertBitmap( BufferImage& destBitmap,
1183                                         FT_Bitmap srcBitmap )
1184 {
1185   if( srcBitmap.width*srcBitmap.rows > 0 )
1186   {
1187     switch( srcBitmap.pixel_mode )
1188     {
1189       case FT_PIXEL_MODE_GRAY:
1190       {
1191         if( srcBitmap.pitch == static_cast< int >( srcBitmap.width ) )
1192         {
1193           destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
1194
1195           PixelBuffer* destBuffer = destBitmap.GetBuffer();
1196           if( destBuffer )
1197           {
1198             memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
1199           }
1200           else
1201           {
1202             DALI_LOG_ERROR( "GetBuffer returns null\n" );
1203           }
1204         }
1205         break;
1206       }
1207
1208 #ifdef FREETYPE_BITMAP_SUPPORT
1209       case FT_PIXEL_MODE_BGRA:
1210       {
1211         if ( srcBitmap.pitch == static_cast< int >( srcBitmap.width << 2 ) )
1212         {
1213           destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::BGRA8888 );
1214
1215           PixelBuffer* destBuffer = destBitmap.GetBuffer();
1216           if( destBuffer )
1217           {
1218             memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows*4 );
1219           }
1220           else
1221           {
1222             DALI_LOG_ERROR( "GetBuffer returns null\n" );
1223           }
1224         }
1225         break;
1226       }
1227 #endif
1228       default:
1229       {
1230         DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" );
1231         break;
1232       }
1233     }
1234   }
1235 }
1236
1237 bool FontClient::Plugin::FindFont( const FontPath& path,
1238                                    PointSize26Dot6 pointSize,
1239                                    FaceIndex faceIndex,
1240                                    FontId& fontId ) const
1241 {
1242   fontId = 0u;
1243   for( std::vector<CacheItem>::const_iterator it = mFontCache.begin(),
1244          endIt = mFontCache.end();
1245        it != endIt;
1246        ++it, ++fontId )
1247   {
1248     const CacheItem& cacheItem = *it;
1249
1250     if( cacheItem.mPointSize == pointSize &&
1251         cacheItem.mFaceIndex == faceIndex &&
1252         cacheItem.mPath == path )
1253     {
1254       ++fontId;
1255       return true;
1256     }
1257   }
1258
1259   return false;
1260 }
1261
1262 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1263                                             FontDescriptionId& validatedFontId )
1264 {
1265   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont fontDescription family(%s)\n", fontDescription.family.c_str() );
1266
1267   validatedFontId = 0u;
1268
1269   for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
1270          endIt = mValidatedFontCache.end();
1271        it != endIt;
1272        ++it )
1273   {
1274     const FontDescriptionCacheItem& item = *it;
1275
1276     if( !fontDescription.family.empty() &&
1277         ( fontDescription.family == item.fontDescription.family ) &&
1278         ( fontDescription.width == item.fontDescription.width ) &&
1279         ( fontDescription.weight == item.fontDescription.weight ) &&
1280         ( fontDescription.slant == item.fontDescription.slant ) )
1281     {
1282       validatedFontId = item.index;
1283
1284       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont validated font family(%s) font id (%u) \n", fontDescription.family.c_str(), validatedFontId );
1285
1286       return true;
1287     }
1288   }
1289
1290   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont NOT VALIDATED return false\n" );
1291
1292   return false;
1293 }
1294
1295 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
1296                                                FontList*& fontList )
1297 {
1298   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList fontDescription family(%s)\n", fontDescription.family.c_str() );
1299
1300   fontList = NULL;
1301
1302   for( std::vector<FallbackCacheItem>::const_iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
1303        it != endIt;
1304        ++it )
1305   {
1306     const FallbackCacheItem& item = *it;
1307
1308     if( !fontDescription.family.empty() &&
1309         ( fontDescription.family == item.fontDescription.family ) &&
1310         ( fontDescription.width == item.fontDescription.width ) &&
1311         ( fontDescription.weight == item.fontDescription.weight ) &&
1312         ( fontDescription.slant == item.fontDescription.slant ) )
1313     {
1314       fontList = item.fallbackFonts;
1315
1316       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList font family(%s) font-list (%p) \n", fontDescription.family.c_str(), fontList );
1317
1318       return true;
1319     }
1320   }
1321
1322   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList NOT FOUND return false\n" );
1323
1324   return false;
1325 }
1326
1327 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1328                                    PointSize26Dot6 pointSize,
1329                                    FontId& fontId )
1330 {
1331   fontId = 0u;
1332
1333   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
1334          endIt = mFontIdCache.end();
1335        it != endIt;
1336        ++it )
1337   {
1338     const FontIdCacheItem& item = *it;
1339
1340     if( ( validatedFontId == item.validatedFontId ) &&
1341         ( pointSize == item.pointSize ) )
1342     {
1343       fontId = item.fontId;
1344       return true;
1345     }
1346   }
1347
1348   return false;
1349 }
1350
1351 bool FontClient::Plugin::IsScalable( const FontPath& path )
1352 {
1353   FT_Face ftFace;
1354   int error = FT_New_Face( mFreeTypeLibrary,
1355                            path.c_str(),
1356                            0,
1357                            &ftFace );
1358   if( FT_Err_Ok != error )
1359   {
1360     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1361   }
1362   return ( ftFace->num_fixed_sizes == 0 );
1363 }
1364
1365 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1366 {
1367   // Create a font pattern.
1368   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1369
1370   FcResult result = FcResultMatch;
1371
1372   // match the pattern
1373   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1374   bool isScalable = true;
1375
1376   if( match )
1377   {
1378     // Get the path to the font file name.
1379     FontPath path;
1380     GetFcString( match, FC_FILE, path );
1381     isScalable = IsScalable( path );
1382   }
1383   else
1384   {
1385     DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1386                     fontDescription.family.c_str(),
1387                     fontDescription.width,
1388                     fontDescription.weight,
1389                     fontDescription.slant );
1390   }
1391   FcPatternDestroy( fontFamilyPattern );
1392   FcPatternDestroy( match );
1393   return isScalable;
1394 }
1395
1396 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1397 {
1398   // Empty the caller container
1399   sizes.Clear();
1400
1401   FT_Face ftFace;
1402   int error = FT_New_Face( mFreeTypeLibrary,
1403                            path.c_str(),
1404                            0,
1405                            &ftFace );
1406   if( FT_Err_Ok != error )
1407   {
1408     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1409   }
1410
1411   // Fetch the number of fixed sizes available
1412   if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1413   {
1414     for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1415     {
1416       sizes.PushBack( ftFace->available_sizes[ i ].size );
1417     }
1418   }
1419 }
1420
1421 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1422                                         Vector< PointSize26Dot6 >& sizes )
1423 {
1424   // Create a font pattern.
1425   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1426
1427   FcResult result = FcResultMatch;
1428
1429   // match the pattern
1430   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1431
1432   if( match )
1433   {
1434     // Get the path to the font file name.
1435     FontPath path;
1436     GetFcString( match, FC_FILE, path );
1437     GetFixedSizes( path, sizes );
1438   }
1439   else
1440   {
1441     DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1442                     fontDescription.family.c_str(),
1443                     fontDescription.width,
1444                     fontDescription.weight,
1445                     fontDescription.slant );
1446   }
1447   FcPatternDestroy( match );
1448   FcPatternDestroy( fontFamilyPattern );
1449 }
1450
1451 } // namespace Internal
1452
1453 } // namespace TextAbstraction
1454
1455 } // namespace Dali