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