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