Merge "Updated Indicator to use SetTexture" into devel/master
[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         PixelData 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 PixelData FontClient::Plugin::CreateBitmap( FontId fontId,
875                                               GlyphIndex glyphIndex )
876 {
877   PixelData 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( PixelData& 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           unsigned int bufferSize( srcBitmap.width * srcBitmap.rows );
1279           unsigned char* buffer = new unsigned char[bufferSize];
1280           memcpy( buffer, srcBitmap.buffer,bufferSize );
1281           destBitmap = PixelData::New( buffer, bufferSize, srcBitmap.width, srcBitmap.rows, Pixel::L8, PixelData::DELETE_ARRAY );
1282         }
1283         break;
1284       }
1285
1286 #ifdef FREETYPE_BITMAP_SUPPORT
1287       case FT_PIXEL_MODE_BGRA:
1288       {
1289         if ( srcBitmap.pitch == static_cast< int >( srcBitmap.width << 2 ) )
1290         {
1291           unsigned int bufferSize( srcBitmap.width * srcBitmap.rows * 4 );
1292           unsigned char* buffer = new unsigned char[bufferSize];
1293           memcpy( buffer, srcBitmap.buffer,bufferSize );
1294           destBitmap = PixelData::New( buffer, bufferSize, srcBitmap.width, srcBitmap.rows, Pixel::BGRA8888, PixelData::DELETE_ARRAY );
1295         }
1296         break;
1297       }
1298 #endif
1299       default:
1300       {
1301         DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" );
1302         break;
1303       }
1304     }
1305   }
1306 }
1307
1308 bool FontClient::Plugin::FindFont( const FontPath& path,
1309                                    PointSize26Dot6 requestedPointSize,
1310                                    FaceIndex faceIndex,
1311                                    FontId& fontId ) const
1312 {
1313   fontId = 0u;
1314   for( std::vector<CacheItem>::const_iterator it = mFontCache.begin(),
1315          endIt = mFontCache.end();
1316        it != endIt;
1317        ++it, ++fontId )
1318   {
1319     const CacheItem& cacheItem = *it;
1320
1321     if( cacheItem.mRequestedPointSize == requestedPointSize &&
1322         cacheItem.mFaceIndex == faceIndex &&
1323         cacheItem.mPath == path )
1324     {
1325       ++fontId;
1326       return true;
1327     }
1328   }
1329
1330   return false;
1331 }
1332
1333 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1334                                             FontDescriptionId& validatedFontId )
1335 {
1336   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont fontDescription family(%s)\n", fontDescription.family.c_str() );
1337
1338   validatedFontId = 0u;
1339
1340   for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
1341          endIt = mValidatedFontCache.end();
1342        it != endIt;
1343        ++it )
1344   {
1345     const FontDescriptionCacheItem& item = *it;
1346
1347     if( !fontDescription.family.empty() &&
1348         ( fontDescription.family == item.fontDescription.family ) &&
1349         ( fontDescription.width == item.fontDescription.width ) &&
1350         ( fontDescription.weight == item.fontDescription.weight ) &&
1351         ( fontDescription.slant == item.fontDescription.slant ) )
1352     {
1353       validatedFontId = item.index;
1354
1355       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont validated font family(%s) font id (%u) \n", fontDescription.family.c_str(), validatedFontId );
1356
1357       return true;
1358     }
1359   }
1360
1361   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont NOT VALIDATED return false\n" );
1362
1363   return false;
1364 }
1365
1366 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
1367                                                FontList*& fontList )
1368 {
1369   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList fontDescription family(%s)\n", fontDescription.family.c_str() );
1370
1371   fontList = NULL;
1372
1373   for( std::vector<FallbackCacheItem>::const_iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
1374        it != endIt;
1375        ++it )
1376   {
1377     const FallbackCacheItem& item = *it;
1378
1379     if( !fontDescription.family.empty() &&
1380         ( fontDescription.family == item.fontDescription.family ) &&
1381         ( fontDescription.width == item.fontDescription.width ) &&
1382         ( fontDescription.weight == item.fontDescription.weight ) &&
1383         ( fontDescription.slant == item.fontDescription.slant ) )
1384     {
1385       fontList = item.fallbackFonts;
1386
1387       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList font family(%s) font-list (%p) \n", fontDescription.family.c_str(), fontList );
1388
1389       return true;
1390     }
1391   }
1392
1393   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList NOT FOUND return false\n" );
1394
1395   return false;
1396 }
1397
1398 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1399                                    PointSize26Dot6 requestedPointSize,
1400                                    FontId& fontId )
1401 {
1402   fontId = 0u;
1403
1404   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
1405          endIt = mFontIdCache.end();
1406        it != endIt;
1407        ++it )
1408   {
1409     const FontIdCacheItem& item = *it;
1410
1411     if( ( validatedFontId == item.validatedFontId ) &&
1412         ( requestedPointSize == item.requestedPointSize ) )
1413     {
1414       fontId = item.fontId;
1415       return true;
1416     }
1417   }
1418
1419   return false;
1420 }
1421
1422 bool FontClient::Plugin::IsScalable( const FontPath& path )
1423 {
1424   FT_Face ftFace;
1425   int error = FT_New_Face( mFreeTypeLibrary,
1426                            path.c_str(),
1427                            0,
1428                            &ftFace );
1429   if( FT_Err_Ok != error )
1430   {
1431     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1432   }
1433   return ( ftFace->num_fixed_sizes == 0 );
1434 }
1435
1436 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1437 {
1438   // Create a font pattern.
1439   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1440
1441   FcResult result = FcResultMatch;
1442
1443   // match the pattern
1444   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1445   bool isScalable = true;
1446
1447   if( match )
1448   {
1449     // Get the path to the font file name.
1450     FontPath path;
1451     GetFcString( match, FC_FILE, path );
1452     isScalable = IsScalable( path );
1453   }
1454   else
1455   {
1456     DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1457                     fontDescription.family.c_str(),
1458                     fontDescription.width,
1459                     fontDescription.weight,
1460                     fontDescription.slant );
1461   }
1462   FcPatternDestroy( fontFamilyPattern );
1463   FcPatternDestroy( match );
1464   return isScalable;
1465 }
1466
1467 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1468 {
1469   // Empty the caller container
1470   sizes.Clear();
1471
1472   FT_Face ftFace;
1473   int error = FT_New_Face( mFreeTypeLibrary,
1474                            path.c_str(),
1475                            0,
1476                            &ftFace );
1477   if( FT_Err_Ok != error )
1478   {
1479     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1480   }
1481
1482   // Fetch the number of fixed sizes available
1483   if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1484   {
1485     for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1486     {
1487       sizes.PushBack( ftFace->available_sizes[ i ].size );
1488     }
1489   }
1490 }
1491
1492 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1493                                         Vector< PointSize26Dot6 >& sizes )
1494 {
1495   // Create a font pattern.
1496   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1497
1498   FcResult result = FcResultMatch;
1499
1500   // match the pattern
1501   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1502
1503   if( match )
1504   {
1505     // Get the path to the font file name.
1506     FontPath path;
1507     GetFcString( match, FC_FILE, path );
1508     GetFixedSizes( path, sizes );
1509   }
1510   else
1511   {
1512     DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1513                     fontDescription.family.c_str(),
1514                     fontDescription.width,
1515                     fontDescription.weight,
1516                     fontDescription.slant );
1517   }
1518   FcPatternDestroy( match );
1519   FcPatternDestroy( fontFamilyPattern );
1520 }
1521
1522 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize,  const FontPath& path )
1523 {
1524   FontDescription description;
1525   description.path = path;
1526   description.family = FontFamily( ftFace->family_name );
1527   description.weight = FontWeight::NORMAL;
1528   description.width = FontWidth::NORMAL;
1529   description.slant = FontSlant::NORMAL;
1530
1531   // Note FreeType doesn't give too much info to build a proper font style.
1532   if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1533   {
1534     description.slant = FontSlant::ITALIC;
1535   }
1536   if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1537   {
1538     description.weight = FontWeight::BOLD;
1539   }
1540
1541   FontDescriptionId validatedFontId = 0u;
1542   if( !FindValidatedFont( description,
1543                           validatedFontId ) )
1544   {
1545     // Set the index to the vector of paths to font file names.
1546     validatedFontId = mFontDescriptionCache.size();
1547
1548     // Add the path to the cache.
1549     mFontDescriptionCache.push_back( description );
1550
1551     // Cache the index and the font's description.
1552     FontDescriptionCacheItem item( description,
1553                                    validatedFontId );
1554
1555     mValidatedFontCache.push_back( item );
1556
1557     // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
1558     mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
1559                                              requestedPointSize,
1560                                              id ) );
1561   }
1562 }
1563
1564 } // namespace Internal
1565
1566 } // namespace TextAbstraction
1567
1568 } // namespace Dali