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