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