[4.0] Caching FcPattern object when using FcCharSetHasChar
[platform/core/uifw/dali-adaptor.git] / text / dali / internal / text-abstraction / font-client-plugin-impl.cpp
1 /*
2  * Copyright (c) 2017 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
24 #include <dali/public-api/common/dali-vector.h>
25 #include <dali/public-api/common/vector-wrapper.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/integration-api/platform-abstraction.h>
28 #include <dali/internal/text-abstraction/font-client-helper.h>
29 #include <platform-abstractions/portable/image-operations.h>
30 #include <adaptor-impl.h>
31
32 // EXTERNAL INCLUDES
33 #include <fontconfig/fontconfig.h>
34
35 namespace
36 {
37
38 #if defined(DEBUG_ENABLED)
39 Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
40 #endif
41
42 /**
43  * Conversion from Fractional26.6 to float
44  */
45 const float FROM_266 = 1.0f / 64.0f;
46 const float POINTS_PER_INCH = 72.f;
47
48 const std::string FONT_FORMAT( "TrueType" );
49 const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
50 const int DEFAULT_FONT_WIDTH  = 100; // normal
51 const int DEFAULT_FONT_WEIGHT =  80; // normal
52 const int DEFAULT_FONT_SLANT  =   0; // normal
53
54 const uint32_t ELLIPSIS_CHARACTER = 0x2026;
55
56 // http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
57
58 // NONE            -1  --> DEFAULT_FONT_WIDTH (NORMAL) will be used.
59 // ULTRA_CONDENSED 50
60 // EXTRA_CONDENSED 63
61 // CONDENSED       75
62 // SEMI_CONDENSED  87
63 // NORMAL         100
64 // SEMI_EXPANDED  113
65 // EXPANDED       125
66 // EXTRA_EXPANDED 150
67 // ULTRA_EXPANDED 200
68 const int FONT_WIDTH_TYPE_TO_INT[] = { -1, 50, 63, 75, 87, 100, 113, 125, 150, 200 };
69 const unsigned int NUM_FONT_WIDTH_TYPE = sizeof( FONT_WIDTH_TYPE_TO_INT ) / sizeof( int );
70
71 // NONE                       -1  --> DEFAULT_FONT_WEIGHT (NORMAL) will be used.
72 // THIN                        0
73 // ULTRA_LIGHT, EXTRA_LIGHT   40
74 // LIGHT                      50
75 // DEMI_LIGHT, SEMI_LIGHT     55
76 // BOOK                       75
77 // NORMAL, REGULAR            80
78 // MEDIUM                    100
79 // DEMI_BOLD, SEMI_BOLD      180
80 // BOLD                      200
81 // ULTRA_BOLD, EXTRA_BOLD    205
82 // BLACK, HEAVY, EXTRA_BLACK 210
83 const int FONT_WEIGHT_TYPE_TO_INT[] = { -1, 0, 40, 50, 55, 75, 80, 100, 180, 200, 205, 210 };
84 const unsigned int NUM_FONT_WEIGHT_TYPE = sizeof( FONT_WEIGHT_TYPE_TO_INT ) / sizeof( int );
85
86 // NONE             -1 --> DEFAULT_FONT_SLANT (NORMAL) will be used.
87 // NORMAL, ROMAN     0
88 // ITALIC          100
89 // OBLIQUE         110
90 const int FONT_SLANT_TYPE_TO_INT[] = { -1, 0, 100, 110 };
91 const unsigned int NUM_FONT_SLANT_TYPE = sizeof( FONT_SLANT_TYPE_TO_INT ) / sizeof( int );
92
93 } // namespace
94
95
96
97 using Dali::Vector;
98
99 namespace Dali
100 {
101
102 namespace TextAbstraction
103 {
104
105 namespace Internal
106 {
107
108 /**
109  * @brief Returns the FontWidth's enum index for the given width value.
110  *
111  * @param[in] width The width value.
112  *
113  * @return The FontWidth's enum index.
114  */
115 FontWidth::Type IntToWidthType( int width )
116 {
117   return static_cast<FontWidth::Type>( ValueToIndex( width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u ) );
118 }
119
120 /**
121  * @brief Returns the FontWeight's enum index for the given weight value.
122  *
123  * @param[in] weight The weight value.
124  *
125  * @return The FontWeight's enum index.
126  */
127 FontWeight::Type IntToWeightType( int weight )
128 {
129   return static_cast<FontWeight::Type>( ValueToIndex( weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u ) );
130 }
131
132 /**
133  * @brief Returns the FontSlant's enum index for the given slant value.
134  *
135  * @param[in] slant The slant value.
136  *
137  * @return The FontSlant's enum index.
138  */
139 FontSlant::Type IntToSlantType( int slant )
140 {
141   return static_cast<FontSlant::Type>( ValueToIndex( slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u ) );
142 }
143
144   FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( const FontDescription& font, FontList* fallbackFonts, CharacterSetList* characterSets )
145 : fontDescription( font ),
146   fallbackFonts( fallbackFonts ),
147   characterSets( characterSets )
148 {
149 }
150
151 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
152                                                                         FontDescriptionId index )
153 : fontDescription( fontDescription ),
154   index( index )
155 {
156 }
157
158 FontClient::Plugin::FontIdCacheItem::FontIdCacheItem( FontDescriptionId validatedFontId,
159                                                       PointSize26Dot6 requestedPointSize,
160                                                       FontId fontId )
161 : validatedFontId( validatedFontId ),
162   requestedPointSize( requestedPointSize ),
163   fontId( fontId )
164 {
165 }
166
167 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
168                                                           const FontPath& path,
169                                                           PointSize26Dot6 requestedPointSize,
170                                                           FaceIndex face,
171                                                           const FontMetrics& metrics )
172 : mFreeTypeFace( ftFace ),
173   mPath( path ),
174   mRequestedPointSize( requestedPointSize ),
175   mFaceIndex( face ),
176   mMetrics( metrics ),
177   mCharacterSet( NULL ),
178   mFixedWidthPixels( 0.0f ),
179   mFixedHeightPixels( 0.0f ),
180   mVectorFontId( 0 ),
181   mIsFixedSizeBitmap( false ),
182   mHasColorTables( false )
183 {
184 }
185
186 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
187                                                           const FontPath& path,
188                                                           PointSize26Dot6 requestedPointSize,
189                                                           FaceIndex face,
190                                                           const FontMetrics& metrics,
191                                                           float fixedWidth,
192                                                           float fixedHeight,
193                                                           bool hasColorTables )
194 : mFreeTypeFace( ftFace ),
195   mPath( path ),
196   mRequestedPointSize( requestedPointSize ),
197   mFaceIndex( face ),
198   mMetrics( metrics ),
199   mCharacterSet( NULL ),
200   mFixedWidthPixels( fixedWidth ),
201   mFixedHeightPixels( fixedHeight ),
202   mVectorFontId( 0 ),
203   mIsFixedSizeBitmap( true ),
204   mHasColorTables( hasColorTables )
205 {
206 }
207
208 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
209                             unsigned int verticalDpi )
210 : mFreeTypeLibrary( NULL ),
211   mDpiHorizontal( horizontalDpi ),
212   mDpiVertical( verticalDpi ),
213   mDefaultFontDescription(),
214   mSystemFonts(),
215   mDefaultFonts(),
216   mFontCache(),
217   mValidatedFontCache(),
218   mFontDescriptionCache( 1u ),
219   mCharacterSetCache(),
220   mFontIdCache(),
221   mVectorFontCache( NULL ),
222   mEllipsisCache(),
223   mDefaultFontDescriptionCached( false )
224 {
225   mCharacterSetCache.Resize( 1u );
226
227   int error = FT_Init_FreeType( &mFreeTypeLibrary );
228   if( FT_Err_Ok != error )
229   {
230     DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Init error: %d\n", error );
231   }
232
233 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
234   mVectorFontCache = new VectorFontCache( mFreeTypeLibrary );
235 #endif
236
237 }
238
239 FontClient::Plugin::~Plugin()
240 {
241   for( std::vector<FallbackCacheItem>::iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
242        it != endIt;
243        ++it )
244   {
245     FallbackCacheItem& item = *it;
246
247     if( item.fallbackFonts )
248     {
249       delete item.fallbackFonts;
250       delete item.characterSets;
251       item.fallbackFonts = NULL;
252       item.characterSets = NULL;
253     }
254   }
255
256 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
257   delete mVectorFontCache;
258 #endif
259   DestroyMatchedPatterns();
260   FT_Done_FreeType( mFreeTypeLibrary );
261 }
262
263 void FontClient::Plugin::ClearCache()
264 {
265   mFontCache.clear();
266   mValidatedFontCache.clear();
267   mFontDescriptionCache.clear();
268   mFontDescriptionCache.resize( 1u );
269
270   mCharacterSetCache.Clear();
271   mCharacterSetCache.Resize( 1u );
272
273   mFontIdCache.clear();
274   mFallbackCache.clear();
275
276   mEllipsisCache.Clear();
277   mSystemFonts.clear();
278   mDefaultFonts.clear();
279   mDefaultFontDescriptionCached = false;
280   mDefaultFontCharacterSets.Clear();
281   mDefaultFontDescription = FontDescription();
282   DestroyMatchedPatterns();
283 }
284
285 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
286                                  unsigned int verticalDpi )
287 {
288   mDpiHorizontal = horizontalDpi;
289   mDpiVertical = verticalDpi;
290 }
291
292 void FontClient::Plugin::ResetSystemDefaults()
293 {
294   mDefaultFontDescriptionCached = false;
295 }
296
297 void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList )
298 {
299   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::SetFontList\n" );
300   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
301   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
302   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
303   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
304
305   fontList.clear();
306
307   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
308
309   FcResult result = FcResultMatch;
310
311   // Match the pattern.
312   FcFontSet* fontSet = FcFontSort( NULL /* use default configure */,
313                                    fontFamilyPattern,
314                                    false /* don't trim */,
315                                    NULL,
316                                    &result );
317
318   if( NULL != fontSet )
319   {
320     DALI_LOG_INFO( gLogFilter, Debug::General, "  number of fonts found : [%d]\n", fontSet->nfont );
321     // Reserve some space to avoid reallocations.
322     fontList.reserve( fontSet->nfont );
323
324     for( int i = 0u; i < fontSet->nfont; ++i )
325     {
326       FcPattern* fontPattern = fontSet->fonts[i];
327
328       FontPath path;
329
330       // Skip fonts with no path
331       if( GetFcString( fontPattern, FC_FILE, path ) )
332       {
333         FcCharSet* characterSet = NULL;
334         FcPatternGetCharSet( fontPattern, FC_CHARSET, 0u, &characterSet );
335
336         characterSetList.PushBack( characterSet );
337         fontList.push_back( FontDescription() );
338         FontDescription& newFontDescription = fontList.back();
339
340         newFontDescription.path = path;
341
342         int width = 0;
343         int weight = 0;
344         int slant = 0;
345         GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
346         GetFcInt( fontPattern, FC_WIDTH, width );
347         GetFcInt( fontPattern, FC_WEIGHT, weight );
348         GetFcInt( fontPattern, FC_SLANT, slant );
349         newFontDescription.width = IntToWidthType( width );
350         newFontDescription.weight = IntToWeightType( weight );
351         newFontDescription.slant = IntToSlantType( slant );
352
353         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  description; family : [%s]\n", newFontDescription.family.c_str() );
354         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", newFontDescription.path.c_str() );
355         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[newFontDescription.width] );
356         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[newFontDescription.weight] );
357         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[newFontDescription.slant] );
358       }
359     }
360
361     FcFontSetDestroy( fontSet );
362   }
363   else
364   {
365     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  No fonts found.\n" );
366   }
367
368   FcPatternDestroy( fontFamilyPattern );
369   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::SetFontList\n" );
370 }
371
372 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
373 {
374   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultFonts\n" );
375
376   if( mDefaultFonts.empty() )
377   {
378     FontDescription fontDescription;
379     fontDescription.family = DEFAULT_FONT_FAMILY_NAME;  // todo This could be set to the Platform font
380     fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
381     fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
382     fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
383     SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets );
384   }
385
386   defaultFonts = mDefaultFonts;
387
388   DALI_LOG_INFO( gLogFilter, Debug::General, "  number of default fonts : [%d]\n", mDefaultFonts.size() );
389   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultFonts\n" );
390 }
391
392 void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
393 {
394   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultPlatformFontDescription\n");
395
396   if( !mDefaultFontDescriptionCached )
397   {
398     // Clear any font config stored info in the caches.
399     mDefaultFontCharacterSets.Clear();
400     mCharacterSetCache.Clear();
401
402     for( std::vector<FallbackCacheItem>::iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end(); it != endIt; ++it )
403     {
404       FallbackCacheItem& item = *it;
405
406       item.characterSets->Clear();
407     }
408
409     for( std::vector<FontFaceCacheItem>::iterator it = mFontCache.begin(), endIt = mFontCache.end(); it != endIt; ++it )
410     {
411       FontFaceCacheItem& item = *it;
412
413       // Set the character set pointer as null. Will be created again the next time IsCharacterSupportedByFont()
414       item.mCharacterSet = NULL;
415     }
416
417     // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
418     FcInitReinitialize();
419
420     FcPattern* matchPattern = FcPatternCreate();
421
422     if( matchPattern )
423     {
424       FcConfigSubstitute( NULL, matchPattern, FcMatchPattern );
425       FcDefaultSubstitute( matchPattern );
426
427       FcCharSet* characterSet = NULL;
428       MatchFontDescriptionToPattern( matchPattern, mDefaultFontDescription, &characterSet );
429       FcPatternDestroy( matchPattern );
430     }
431
432     // Create again the character sets as they are not valid after FcInitReinitialize()
433
434     for( FontList::const_iterator it = mDefaultFonts.begin(), endIt = mDefaultFonts.end(); it != endIt; ++it )
435     {
436       const FontDescription& description = *it;
437
438       mDefaultFontCharacterSets.PushBack( CreateCharacterSetFromDescription( description ) );
439     }
440
441     for( FontList::const_iterator it = mFontDescriptionCache.begin(), endIt = mFontDescriptionCache.end(); it != endIt; ++it )
442     {
443       const FontDescription& description = *it;
444
445       mCharacterSetCache.PushBack( CreateCharacterSetFromDescription( description ) );
446     }
447
448     for( std::vector<FallbackCacheItem>::iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end(); it != endIt; ++it )
449     {
450       FallbackCacheItem& item = *it;
451
452       if( NULL != item.fallbackFonts )
453       {
454         if( NULL == item.characterSets )
455         {
456           item.characterSets = new CharacterSetList;
457         }
458
459         for( FontList::const_iterator flIt = item.fallbackFonts->begin(), flEndIt = item.fallbackFonts->end(); flIt != flEndIt; ++flIt )
460         {
461           const FontDescription& description = *flIt;
462           item.characterSets->PushBack( CreateCharacterSetFromDescription( description ) );
463         }
464       }
465     }
466
467     mDefaultFontDescriptionCached = true;
468   }
469
470   fontDescription.path   = mDefaultFontDescription.path;
471   fontDescription.family = mDefaultFontDescription.family;
472   fontDescription.width  = mDefaultFontDescription.width;
473   fontDescription.weight = mDefaultFontDescription.weight;
474   fontDescription.slant  = mDefaultFontDescription.slant;
475
476   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
477   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
478   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
479   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
480   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
481   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultPlatformFontDescription\n");
482 }
483
484 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
485 {
486   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetSystemFonts\n");
487
488   if( mSystemFonts.empty() )
489   {
490     InitSystemFonts();
491   }
492
493   systemFonts = mSystemFonts;
494   DALI_LOG_INFO( gLogFilter, Debug::General, "  number of system fonts : [%d]\n", mSystemFonts.size() );
495   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetSystemFonts\n");
496 }
497
498 void FontClient::Plugin::GetDescription( FontId id,
499                                          FontDescription& fontDescription ) const
500 {
501   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDescription\n");
502   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
503
504   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
505          endIt = mFontIdCache.end();
506        it != endIt;
507        ++it )
508   {
509     const FontIdCacheItem& item = *it;
510
511     if( item.fontId == id )
512     {
513       fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
514
515       DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
516       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
517       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
518       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
519       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
520       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
521       return;
522     }
523   }
524
525   DALI_LOG_INFO( gLogFilter, Debug::General, "  No description found for the font ID %d\n", id );
526   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
527 }
528
529 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
530 {
531   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetPointSize\n");
532   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
533   const FontId index = id - 1u;
534
535   if( ( id > 0u ) &&
536       ( index < mFontCache.size() ) )
537   {
538     DALI_LOG_INFO( gLogFilter, Debug::General, "  point size : %d\n", ( *( mFontCache.begin() + index ) ).mRequestedPointSize );
539     DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
540     return ( *( mFontCache.begin() + index ) ).mRequestedPointSize;
541   }
542   else
543   {
544     DALI_LOG_INFO( gLogFilter, Debug::General, "  Invalid font ID %d\n", id );
545   }
546
547   DALI_LOG_INFO( gLogFilter, Debug::General, "  default point size : %d\n", TextAbstraction::FontClient::DEFAULT_POINT_SIZE );
548   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
549   return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
550 }
551
552 bool FontClient::Plugin::IsCharacterSupportedByFont( FontId fontId, Character character )
553 {
554   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::IsCharacterSupportedByFont\n");
555   DALI_LOG_INFO( gLogFilter, Debug::General, "    font id : %d\n", fontId );
556   DALI_LOG_INFO( gLogFilter, Debug::General, "  character : %p\n", character );
557
558   if( ( fontId < 1u ) || ( fontId > mFontCache.size() ) )
559   {
560     DALI_LOG_INFO( gLogFilter, Debug::General, "  Invalid font id. Number of items in the cache: %d\n",mFontCache.size());
561     DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
562     return false;
563   }
564
565   --fontId;
566
567   bool isSupported = false;
568
569   FontFaceCacheItem& cacheItem = mFontCache[fontId];
570
571   if( NULL == cacheItem.mCharacterSet )
572   {
573     // Create again the character set.
574     // It can be null if the ResetSystemDefaults() method has been called.
575
576     FontDescription description;
577     description.path = cacheItem.mPath;
578     description.family = FontFamily( cacheItem.mFreeTypeFace->family_name );
579     description.weight = FontWeight::NONE;
580     description.width = FontWidth::NONE;
581     description.slant = FontSlant::NONE;
582
583     // Note FreeType doesn't give too much info to build a proper font style.
584     if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC )
585     {
586       description.slant = FontSlant::ITALIC;
587     }
588     if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_BOLD )
589     {
590       description.weight = FontWeight::BOLD;
591     }
592
593     cacheItem.mCharacterSet = CreateCharacterSetFromDescription( description );
594   }
595
596   isSupported = FcCharSetHasChar( cacheItem.mCharacterSet, character );
597
598   DALI_LOG_INFO( gLogFilter, Debug::General, "  is supported : %s\n", (isSupported ? "true" : "false") );
599   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
600   return isSupported;
601 }
602
603 FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList,
604                                                  const CharacterSetList& characterSetList,
605                                                  Character character,
606                                                  PointSize26Dot6 requestedPointSize,
607                                                  bool preferColor )
608 {
609   DALI_ASSERT_DEBUG( ( fontList.size() == characterSetList.Count() ) && "FontClient::Plugin::FindFontForCharacter. Different number of fonts and character sets." );
610
611   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFontForCharacter\n" );
612   DALI_LOG_INFO( gLogFilter, Debug::General, "           character : %p\n", character );
613   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
614   DALI_LOG_INFO( gLogFilter, Debug::General, "         preferColor : %s\n", ( preferColor ? "true" : "false" ) );
615
616   FontId fontId = 0u;
617   bool foundColor = false;
618
619   DALI_LOG_INFO( gLogFilter, Debug::General, "  number of fonts : %d\n", fontList.size() );
620
621   // Traverse the list of fonts.
622   // Check for each font if supports the character.
623   for( unsigned int index = 0u, numberOfFonts = fontList.size(); index < numberOfFonts; ++index )
624   {
625     const FontDescription& description = fontList[index];
626     const FcCharSet* const characterSet = characterSetList[index];
627
628     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  description; family : [%s]\n", description.family.c_str() );
629     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", description.path.c_str() );
630     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[description.width] );
631     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[description.weight] );
632     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[description.slant] );
633
634     bool foundInRanges = false;
635     if( NULL != characterSet )
636     {
637       foundInRanges = FcCharSetHasChar( characterSet, character );
638     }
639
640     if( foundInRanges )
641     {
642       fontId = GetFontId( description,
643                           requestedPointSize,
644                           0u );
645
646       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "     font id : %d\n", fontId );
647
648       if( preferColor )
649       {
650         if( ( fontId > 0 ) &&
651             ( fontId - 1u < mFontCache.size() ) )
652         {
653           const FontFaceCacheItem& item = mFontCache[fontId - 1u];
654
655           foundColor = item.mHasColorTables;
656         }
657
658         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  foundColor : %s\n", ( foundColor ? "true" : "false" ) );
659       }
660
661       // Keep going unless we prefer a different (color) font.
662       if( !preferColor || foundColor )
663       {
664         break;
665       }
666     }
667   }
668
669   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", fontId );
670   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFontForCharacter\n" );
671   return fontId;
672 }
673
674 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
675                                             PointSize26Dot6 requestedPointSize,
676                                             bool preferColor )
677 {
678   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindDefaultFont\n" );
679   DALI_LOG_INFO( gLogFilter, Debug::General, "           character : %p\n", charcode );
680   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
681   DALI_LOG_INFO( gLogFilter, Debug::General, "         preferColor : %s\n", ( preferColor ? "true" : "false" ) );
682
683   FontId fontId(0);
684
685   // Create the list of default fonts if it has not been created.
686   if( mDefaultFonts.empty() )
687   {
688     FontDescription fontDescription;
689     fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
690     fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
691     fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
692     fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
693
694     SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets );
695   }
696   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of default fonts : %d\n", mDefaultFonts.size() );
697
698
699   // Traverse the list of default fonts.
700   // Check for each default font if supports the character.
701   fontId = FindFontForCharacter( mDefaultFonts, mDefaultFontCharacterSets, charcode, requestedPointSize, preferColor );
702
703   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", fontId );
704   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindDefaultFont\n" );
705
706   return fontId;
707 }
708
709 FontId FontClient::Plugin::FindFallbackFont( Character charcode,
710                                              const FontDescription& preferredFontDescription,
711                                              PointSize26Dot6 requestedPointSize,
712                                              bool preferColor )
713 {
714   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFont\n" );
715   DALI_LOG_INFO( gLogFilter, Debug::General, "           character : %p\n", charcode );
716   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
717   DALI_LOG_INFO( gLogFilter, Debug::General, "         preferColor : %s\n", ( preferColor ? "true" : "false" ) );
718
719   // The font id to be returned.
720   FontId fontId = 0u;
721
722   FontDescription fontDescription;
723
724   // Fill the font description with the preferred font description and complete with the defaults.
725   fontDescription.family = preferredFontDescription.family.empty() ? DEFAULT_FONT_FAMILY_NAME : preferredFontDescription.family;
726   fontDescription.weight = ( ( FontWeight::NONE == preferredFontDescription.weight ) ? IntToWeightType( DEFAULT_FONT_WEIGHT ) : preferredFontDescription.weight );
727   fontDescription.width = ( ( FontWidth::NONE == preferredFontDescription.width ) ? IntToWidthType( DEFAULT_FONT_WIDTH ) : preferredFontDescription.width );
728   fontDescription.slant = ( ( FontSlant::NONE == preferredFontDescription.slant ) ? IntToSlantType( DEFAULT_FONT_SLANT ) : preferredFontDescription.slant );
729
730   DALI_LOG_INFO( gLogFilter, Debug::General, "  preferredFontDescription --> fontDescription\n" );
731   DALI_LOG_INFO( gLogFilter, Debug::General, "  [%s] --> [%s]\n", preferredFontDescription.family.c_str(), fontDescription.family.c_str() );
732   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  [%s] --> [%s]\n", FontWeight::Name[preferredFontDescription.weight], FontWeight::Name[fontDescription.weight] );
733   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  [%s] --> [%s]\n", FontWidth::Name[preferredFontDescription.width], FontWidth::Name[fontDescription.width] );
734   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  [%s] --> [%s]\n", FontSlant::Name[preferredFontDescription.slant], FontSlant::Name[fontDescription.slant] );
735
736   // Check first if the font's description has been queried before.
737   FontList* fontList = NULL;
738   CharacterSetList* characterSetList = NULL;
739
740   if( !FindFallbackFontList( fontDescription, fontList, characterSetList ) )
741   {
742     fontList = new FontList;
743     characterSetList = new CharacterSetList;
744
745     SetFontList( fontDescription, *fontList, *characterSetList );
746
747     // Add the font-list to the cache.
748     mFallbackCache.push_back( FallbackCacheItem( fontDescription, fontList, characterSetList ) );
749   }
750
751   if( fontList && characterSetList )
752   {
753     fontId = FindFontForCharacter( *fontList, *characterSetList, charcode, requestedPointSize, preferColor );
754   }
755
756   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", fontId );
757   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFont\n");
758   return fontId;
759 }
760
761 FontId FontClient::Plugin::GetFontId( const FontPath& path,
762                                       PointSize26Dot6 requestedPointSize,
763                                       FaceIndex faceIndex,
764                                       bool cacheDescription )
765 {
766   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" );
767   DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
768   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
769
770   FontId id( 0 );
771
772   if( NULL != mFreeTypeLibrary )
773   {
774     FontId foundId(0);
775     if( FindFont( path, requestedPointSize, faceIndex, foundId ) )
776     {
777       id = foundId;
778     }
779     else
780     {
781       id = CreateFont( path, requestedPointSize, faceIndex, cacheDescription );
782     }
783   }
784
785   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
786   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" );
787
788   return id;
789 }
790
791 FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
792                                       PointSize26Dot6 requestedPointSize,
793                                       FaceIndex faceIndex )
794 {
795   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" );
796   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
797   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
798   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
799   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
800   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
801   DALI_LOG_INFO( gLogFilter, Debug::General, "   requestedPointSize : %d\n", requestedPointSize );
802
803   // This method uses three vectors which caches:
804   // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
805   // * The path to font file names.
806   // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
807
808   // 1) Checks in the cache if the font's description has been validated before.
809   //    If it was it gets an index to the vector with paths to font file names. Otherwise,
810   //    retrieves using font config a path to a font file name which matches with the
811   //    font's description. The path is stored in the cache.
812   //
813   // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
814   //    font file names' exists. If exists, it gets the font id. If it doesn't it calls
815   //    the GetFontId() method with the path to the font file name and the point size to
816   //    get the font id.
817
818   // The font id to be returned.
819   FontId fontId = 0u;
820
821   // Check first if the font's description have been validated before.
822   FontDescriptionId validatedFontId = 0u;
823
824   if( !FindValidatedFont( fontDescription,
825                           validatedFontId ) )
826   {
827     // Use font config to validate the font's description.
828     ValidateFont( fontDescription,
829                   validatedFontId );
830   }
831
832   // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
833   if( !FindFont( validatedFontId, requestedPointSize, fontId ) )
834   {
835     // Retrieve the font file name path.
836     const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
837
838     // Retrieve the font id. Do not cache the description as it has been already cached.
839     fontId = GetFontId( description.path,
840                         requestedPointSize,
841                         faceIndex,
842                         false );
843
844     mFontCache[fontId-1u].mCharacterSet = mCharacterSetCache[validatedFontId];
845
846     // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
847     mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
848                                              requestedPointSize,
849                                              fontId ) );
850   }
851
852   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", fontId );
853   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" );
854
855   return fontId;
856 }
857
858 void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
859                                        FontDescriptionId& validatedFontId )
860 {
861   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::ValidateFont\n" );
862   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
863   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
864   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
865   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
866   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
867
868   // Create a font pattern.
869   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
870
871   FontDescription description;
872
873   FcCharSet* characterSet = NULL;
874   bool matched = MatchFontDescriptionToPattern( fontFamilyPattern, description, &characterSet );
875   FcPatternDestroy( fontFamilyPattern );
876
877   if( matched && ( NULL != characterSet ) )
878   {
879     // Set the index to the vector of paths to font file names.
880     validatedFontId = mFontDescriptionCache.size();
881
882     DALI_LOG_INFO( gLogFilter, Debug::General, "  matched description; family : [%s]\n", description.family.c_str() );
883     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                         path : [%s]\n", description.path.c_str() );
884     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                        width : [%s]\n", FontWidth::Name[description.width] );
885     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                       weight : [%s]\n", FontWeight::Name[description.weight] );
886     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                        slant : [%s]\n\n", FontSlant::Name[description.slant] );
887     DALI_LOG_INFO( gLogFilter, Debug::General, "  validatedFontId : %d\n", validatedFontId );
888
889     // Add the path to the cache.
890     mFontDescriptionCache.push_back( description );
891     mCharacterSetCache.PushBack( characterSet );
892
893     // Cache the index and the matched font's description.
894     FontDescriptionCacheItem item( description,
895                                    validatedFontId );
896
897     mValidatedFontCache.push_back( item );
898
899     if( ( fontDescription.family != description.family ) ||
900         ( fontDescription.width != description.width )   ||
901         ( fontDescription.weight != description.weight ) ||
902         ( fontDescription.slant != description.slant ) )
903     {
904       // Cache the given font's description if it's different than the matched.
905       FontDescriptionCacheItem item( fontDescription,
906                                      validatedFontId );
907
908       mValidatedFontCache.push_back( item );
909     }
910   }
911   else
912   {
913     DALI_LOG_INFO( gLogFilter, Debug::General, "  font validation failed for font [%s]\n", fontDescription.family.c_str() );
914   }
915
916   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::ValidateFont\n" );
917 }
918
919 void FontClient::Plugin::GetFontMetrics( FontId fontId,
920                                          FontMetrics& metrics )
921 {
922   if( ( fontId > 0 ) &&
923       ( fontId - 1u < mFontCache.size() ) )
924   {
925     const FontFaceCacheItem& font = mFontCache[fontId-1];
926
927     metrics = font.mMetrics;
928
929     // Adjust the metrics if the fixed-size font should be down-scaled
930     if( font.mIsFixedSizeBitmap )
931     {
932       const float desiredFixedSize =  static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
933
934       if( desiredFixedSize > 0.f )
935       {
936         const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
937
938         metrics.ascender = floorf( metrics.ascender * scaleFactor );
939         metrics.descender = floorf( metrics.descender * scaleFactor );
940         metrics.height = floorf( metrics.height * scaleFactor );
941         metrics.underlinePosition = floorf( metrics.underlinePosition * scaleFactor );
942         metrics.underlineThickness = floorf( metrics.underlineThickness * scaleFactor );
943       }
944     }
945   }
946   else
947   {
948     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId );
949   }
950 }
951
952 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
953                                               Character charcode )
954 {
955   GlyphIndex index = 0u;
956
957   if( ( fontId > 0u ) &&
958       ( fontId - 1u < mFontCache.size() ) )
959   {
960     FT_Face ftFace = mFontCache[fontId-1u].mFreeTypeFace;
961
962     index = FT_Get_Char_Index( ftFace, charcode );
963   }
964
965   return index;
966 }
967
968 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
969                                           uint32_t size,
970                                           GlyphType type,
971                                           bool horizontal )
972 {
973   if( VECTOR_GLYPH == type )
974   {
975     return GetVectorMetrics( array, size, horizontal );
976   }
977
978   return GetBitmapMetrics( array, size, horizontal );
979 }
980
981 bool FontClient::Plugin::GetBitmapMetrics( GlyphInfo* array,
982                                            uint32_t size,
983                                            bool horizontal )
984 {
985   bool success( true );
986
987   for( unsigned int i=0; i<size; ++i )
988   {
989     GlyphInfo& glyph = array[i];
990
991     FontId fontId = glyph.fontId;
992
993     if( fontId > 0 &&
994         fontId-1 < mFontCache.size() )
995     {
996       const FontFaceCacheItem& font = mFontCache[fontId-1];
997
998       FT_Face ftFace = font.mFreeTypeFace;
999
1000 #ifdef FREETYPE_BITMAP_SUPPORT
1001       // Check to see if we should be loading a Fixed Size bitmap?
1002       if ( font.mIsFixedSizeBitmap )
1003       {
1004         int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_COLOR );
1005         if ( FT_Err_Ok == error )
1006         {
1007           glyph.width = font.mFixedWidthPixels;
1008           glyph.height = font.mFixedHeightPixels;
1009           glyph.advance = font.mFixedWidthPixels;
1010           glyph.xBearing = 0.0f;
1011           glyph.yBearing = font.mFixedHeightPixels;
1012
1013           // Adjust the metrics if the fixed-size font should be down-scaled
1014           const float desiredFixedSize =  static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
1015
1016           if( desiredFixedSize > 0.f )
1017           {
1018             const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
1019
1020             glyph.width = floorf( glyph.width * scaleFactor );
1021             glyph.height = floorf( glyph.height * scaleFactor );
1022             glyph.advance = floorf( glyph.advance * scaleFactor );
1023             glyph.xBearing = floorf( glyph.xBearing * scaleFactor );
1024             glyph.yBearing = floorf( glyph.yBearing * scaleFactor );
1025
1026             glyph.scaleFactor = scaleFactor;
1027           }
1028         }
1029         else
1030         {
1031           DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetBitmapMetrics. FreeType Bitmap Load_Glyph error %d\n", error );
1032           success = false;
1033         }
1034       }
1035       else
1036 #endif
1037       {
1038         int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_NO_AUTOHINT );
1039
1040         if( FT_Err_Ok == error )
1041         {
1042           glyph.width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
1043           glyph.height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
1044           if( horizontal )
1045           {
1046             glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
1047             glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
1048           }
1049           else
1050           {
1051             glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
1052             glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
1053           }
1054         }
1055         else
1056         {
1057           success = false;
1058         }
1059       }
1060     }
1061     else
1062     {
1063       success = false;
1064     }
1065   }
1066
1067   return success;
1068 }
1069
1070 bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array,
1071                                            uint32_t size,
1072                                            bool horizontal )
1073 {
1074 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
1075   bool success( true );
1076
1077   for( unsigned int i=0; i<size; ++i )
1078   {
1079     FontId fontId = array[i].fontId;
1080
1081     if( fontId > 0 &&
1082         fontId-1 < mFontCache.size() )
1083     {
1084       FontFaceCacheItem& font = mFontCache[fontId-1];
1085
1086       if( ! font.mVectorFontId )
1087       {
1088         font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
1089       }
1090
1091       mVectorFontCache->GetGlyphMetrics( font.mVectorFontId, array[i] );
1092
1093       // Vector metrics are in EMs, convert to pixels
1094       const float scale = ( static_cast<float>( font.mRequestedPointSize ) * FROM_266 ) * static_cast<float>( mDpiVertical ) / POINTS_PER_INCH;
1095       array[i].width    *= scale;
1096       array[i].height   *= scale;
1097       array[i].xBearing *= scale;
1098       array[i].yBearing *= scale;
1099       array[i].advance  *= scale;
1100     }
1101     else
1102     {
1103       success = false;
1104     }
1105   }
1106
1107   return success;
1108 #else
1109   return false;
1110 #endif
1111 }
1112
1113 void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
1114 {
1115   if( ( fontId > 0 ) &&
1116       ( fontId - 1u < mFontCache.size() ) )
1117   {
1118     FT_Face ftFace = mFontCache[fontId - 1u].mFreeTypeFace;
1119
1120     FT_Error error;
1121
1122 #ifdef FREETYPE_BITMAP_SUPPORT
1123     // Check to see if this is fixed size bitmap
1124     if ( mFontCache[fontId - 1u].mIsFixedSizeBitmap )
1125     {
1126       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1127     }
1128     else
1129 #endif
1130     {
1131       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_NO_AUTOHINT );
1132     }
1133     if( FT_Err_Ok == error )
1134     {
1135       FT_Glyph glyph;
1136       error = FT_Get_Glyph( ftFace->glyph, &glyph );
1137
1138       // Convert to bitmap if necessary
1139       if ( FT_Err_Ok == error )
1140       {
1141         if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
1142         {
1143           // Check whether we should create a bitmap for the outline
1144           if( glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0 )
1145           {
1146             // Set up a stroker
1147             FT_Stroker stroker;
1148             error = FT_Stroker_New(mFreeTypeLibrary, &stroker );
1149
1150             if ( FT_Err_Ok == error )
1151             {
1152               FT_Stroker_Set( stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0 );
1153               error = FT_Glyph_StrokeBorder( &glyph, stroker, 0, 1 );
1154
1155               if ( FT_Err_Ok == error )
1156               {
1157                 FT_Stroker_Done( stroker );
1158               }
1159               else
1160               {
1161                 DALI_LOG_ERROR( "FT_Glyph_StrokeBorder Failed with error: %d\n", error );
1162               }
1163             }
1164             else
1165             {
1166               DALI_LOG_ERROR( "FT_Stroker_New Failed with error: %d\n", error );
1167             }
1168           }
1169
1170           error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
1171           if ( FT_Err_Ok == error )
1172           {
1173             FT_BitmapGlyph bitmapGlyph = reinterpret_cast< FT_BitmapGlyph >( glyph );
1174             ConvertBitmap( data, bitmapGlyph->bitmap );
1175           }
1176           else
1177           {
1178             DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Get_Glyph Failed with error: %d\n", error );
1179           }
1180         }
1181         else
1182         {
1183           ConvertBitmap( data, ftFace->glyph->bitmap );
1184         }
1185
1186         // Created FT_Glyph object must be released with FT_Done_Glyph
1187         FT_Done_Glyph( glyph );
1188       }
1189     }
1190     else
1191     {
1192       DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Load_Glyph Failed with error: %d\n", error );
1193     }
1194   }
1195 }
1196
1197 PixelData FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
1198 {
1199   TextAbstraction::FontClient::GlyphBufferData data;
1200
1201   CreateBitmap( fontId, glyphIndex, data, outlineWidth );
1202
1203   return PixelData::New( data.buffer,
1204                          data.width * data.height * Pixel::GetBytesPerPixel( data.format ),
1205                          data.width,
1206                          data.height,
1207                          data.format,
1208                          PixelData::DELETE_ARRAY );
1209 }
1210
1211 void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
1212 {
1213   blob = NULL;
1214   blobLength = 0;
1215
1216 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
1217   if( fontId > 0 &&
1218       fontId-1 < mFontCache.size() )
1219   {
1220     FontFaceCacheItem& font = mFontCache[fontId-1];
1221
1222     if( ! font.mVectorFontId )
1223     {
1224       font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
1225     }
1226
1227     mVectorFontCache->GetVectorBlob( font.mVectorFontId, fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
1228   }
1229 #endif
1230 }
1231
1232 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize )
1233 {
1234   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetEllipsisGlyph\n" );
1235   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize %d.\n", requestedPointSize );
1236
1237   // First look into the cache if there is an ellipsis glyph for the requested point size.
1238   for( Vector<EllipsisItem>::ConstIterator it = mEllipsisCache.Begin(),
1239          endIt = mEllipsisCache.End();
1240        it != endIt;
1241        ++it )
1242   {
1243     const EllipsisItem& item = *it;
1244
1245     if( fabsf( item.requestedPointSize - requestedPointSize ) < Math::MACHINE_EPSILON_1000 )
1246     {
1247       // Use the glyph in the cache.
1248
1249       DALI_LOG_INFO( gLogFilter, Debug::General, "  glyph id %d found in the cache.\n", item.glyph.index );
1250       DALI_LOG_INFO( gLogFilter, Debug::General, "      font %d.\n", item.glyph.fontId );
1251       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
1252
1253       return item.glyph;
1254     }
1255   }
1256
1257   // No glyph has been found. Create one.
1258   mEllipsisCache.PushBack( EllipsisItem() );
1259   EllipsisItem& item = *( mEllipsisCache.End() - 1u );
1260
1261   item.requestedPointSize = requestedPointSize;
1262
1263   // Find a font for the ellipsis glyph.
1264   item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
1265                                        requestedPointSize,
1266                                        false );
1267
1268   // Set the character index to access the glyph inside the font.
1269   item.glyph.index = FT_Get_Char_Index( mFontCache[item.glyph.fontId-1].mFreeTypeFace,
1270                                         ELLIPSIS_CHARACTER );
1271
1272   GetBitmapMetrics( &item.glyph, 1u, true );
1273
1274   DALI_LOG_INFO( gLogFilter, Debug::General, "  glyph id %d found in the cache.\n", item.glyph.index );
1275   DALI_LOG_INFO( gLogFilter, Debug::General, "      font %d.\n", item.glyph.fontId );
1276   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
1277
1278   return item.glyph;
1279 }
1280
1281 bool FontClient::Plugin::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
1282 {
1283   FT_Error error = -1;
1284
1285 #ifdef FREETYPE_BITMAP_SUPPORT
1286   if( ( fontId > 0 ) &&
1287       ( fontId - 1u < mFontCache.size() ) )
1288   {
1289     const FontFaceCacheItem& item = mFontCache[fontId - 1u];
1290     FT_Face ftFace = item.mFreeTypeFace;
1291
1292     // Check to see if this is fixed size bitmap
1293     if( item.mHasColorTables )
1294     {
1295       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1296     }
1297   }
1298 #endif
1299
1300   return FT_Err_Ok == error;
1301 }
1302
1303 bool FontClient::Plugin::AddCustomFontDirectory( const FontPath& path )
1304 {
1305   // NULL as first parameter means the current configuration is used.
1306   return FcConfigAppFontAddDir( NULL, reinterpret_cast<const FcChar8 *>( path.c_str() ) );
1307 }
1308
1309 void FontClient::Plugin::InitSystemFonts()
1310 {
1311   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::InitSystemFonts\n" );
1312
1313   FcFontSet* fontSet = GetFcFontSet();
1314
1315   if( fontSet )
1316   {
1317     DALI_LOG_INFO( gLogFilter, Debug::General, "  number of system fonts : %d\n", fontSet->nfont );
1318
1319     // Reserve some space to avoid reallocations.
1320     mSystemFonts.reserve( fontSet->nfont );
1321
1322     for( int i = 0u; i < fontSet->nfont; ++i )
1323     {
1324       FcPattern* fontPattern = fontSet->fonts[i];
1325
1326       FontPath path;
1327
1328       // Skip fonts with no path
1329       if( GetFcString( fontPattern, FC_FILE, path ) )
1330       {
1331         mSystemFonts.push_back( FontDescription() );
1332         FontDescription& fontDescription = mSystemFonts.back();
1333
1334         fontDescription.path = path;
1335
1336         int width = 0;
1337         int weight = 0;
1338         int slant = 0;
1339         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
1340         GetFcInt( fontPattern, FC_WIDTH, width );
1341         GetFcInt( fontPattern, FC_WEIGHT, weight );
1342         GetFcInt( fontPattern, FC_SLANT, slant );
1343         fontDescription.width = IntToWidthType( width );
1344         fontDescription.weight = IntToWeightType( weight );
1345         fontDescription.slant = IntToSlantType( slant );
1346
1347         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  description; family : [%s]\n", fontDescription.family.c_str() );
1348         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1349         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1350         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1351         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1352       }
1353     }
1354
1355     FcFontSetDestroy( fontSet );
1356   }
1357   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::InitSystemFonts\n" );
1358 }
1359
1360 bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet )
1361 {
1362   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1363
1364   FcResult result = FcResultMatch;
1365   FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
1366
1367   const bool matched = NULL != match;
1368   DALI_LOG_INFO( gLogFilter, Debug::General, "  pattern matched : %s\n", ( matched ? "true" : "false" ) );
1369
1370   if( matched )
1371   {
1372     int width = 0;
1373     int weight = 0;
1374     int slant = 0;
1375     GetFcString( match, FC_FILE, fontDescription.path );
1376     GetFcString( match, FC_FAMILY, fontDescription.family );
1377     GetFcInt( match, FC_WIDTH, width );
1378     GetFcInt( match, FC_WEIGHT, weight );
1379     GetFcInt( match, FC_SLANT, slant );
1380     fontDescription.width = IntToWidthType( width );
1381     fontDescription.weight = IntToWeightType( weight );
1382     fontDescription.slant = IntToSlantType( slant );
1383
1384     // Cache the character ranges.
1385     FcPatternGetCharSet( match, FC_CHARSET, 0u, characterSet );
1386
1387     // destroyed the matched pattern
1388     FcPatternDestroy( match );
1389
1390     DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1391     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1392     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1393     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1394     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1395   }
1396
1397   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1398   return matched;
1399 }
1400
1401 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription ) const
1402 {
1403   // create the cached font family lookup pattern
1404   // a pattern holds a set of names, each name refers to a property of the font
1405   FcPattern* fontFamilyPattern = FcPatternCreate();
1406
1407   if( !fontFamilyPattern )
1408   {
1409     return NULL;
1410   }
1411
1412   // add a property to the pattern for the font family
1413   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
1414
1415   // add a property to the pattern for local setting.
1416   const char* locale = setlocale( LC_MESSAGES, NULL );
1417   if( locale != NULL)
1418   {
1419     FcPatternAddString( fontFamilyPattern, FC_LANG, reinterpret_cast<const FcChar8*>( locale ) );
1420   }
1421
1422   int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
1423   if( width < 0 )
1424   {
1425     // Use default.
1426     width = DEFAULT_FONT_WIDTH;
1427   }
1428
1429   int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
1430   if( weight < 0 )
1431   {
1432     // Use default.
1433     weight = DEFAULT_FONT_WEIGHT;
1434   }
1435
1436   int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
1437   if( slant < 0 )
1438   {
1439     // Use default.
1440     slant = DEFAULT_FONT_SLANT;
1441   }
1442
1443   FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
1444   FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
1445   FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
1446
1447   // Add a property of the pattern, to say we want to match TrueType fonts
1448   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
1449
1450   // modify the config, with the mFontFamilyPatterm
1451   FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
1452
1453   // provide default values for unspecified properties in the font pattern
1454   // e.g. patterns without a specified style or weight are set to Medium
1455   FcDefaultSubstitute( fontFamilyPattern );
1456
1457   return fontFamilyPattern;
1458 }
1459
1460 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
1461 {
1462   // create a new pattern.
1463   // a pattern holds a set of names, each name refers to a property of the font
1464   FcPattern* pattern = FcPatternCreate();
1465
1466   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
1467   FcObjectSet* objectSet = FcObjectSetCreate();
1468
1469   // build an object set from a list of property names
1470   FcObjectSetAdd( objectSet, FC_FILE );
1471   FcObjectSetAdd( objectSet, FC_FAMILY );
1472   FcObjectSetAdd( objectSet, FC_WIDTH );
1473   FcObjectSetAdd( objectSet, FC_WEIGHT );
1474   FcObjectSetAdd( objectSet, FC_SLANT );
1475
1476   // get a list of fonts
1477   // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
1478   FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
1479
1480   // clear up the object set
1481   if( objectSet )
1482   {
1483     FcObjectSetDestroy( objectSet );
1484   }
1485   // clear up the pattern
1486   if( pattern )
1487   {
1488     FcPatternDestroy( pattern );
1489   }
1490
1491   return fontset;
1492 }
1493
1494 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1495                                       const char* const n,
1496                                       std::string& string )
1497 {
1498   FcChar8* file = NULL;
1499   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1500
1501   if( FcResultMatch == retVal )
1502   {
1503     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1504     string.assign( reinterpret_cast<const char*>( file ) );
1505
1506     return true;
1507   }
1508
1509   return false;
1510 }
1511
1512 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
1513 {
1514   const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
1515
1516   if( FcResultMatch == retVal )
1517   {
1518     return true;
1519   }
1520
1521   return false;
1522 }
1523
1524 FontId FontClient::Plugin::CreateFont( const FontPath& path,
1525                                        PointSize26Dot6 requestedPointSize,
1526                                        FaceIndex faceIndex,
1527                                        bool cacheDescription )
1528 {
1529   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::CreateFont\n" );
1530   DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
1531   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1532
1533   FontId id = 0u;
1534
1535   // Create & cache new font face
1536   FT_Face ftFace;
1537   int error = FT_New_Face( mFreeTypeLibrary,
1538                            path.c_str(),
1539                            0,
1540                            &ftFace );
1541
1542   if( FT_Err_Ok == error )
1543   {
1544     // Check if a font is scalable.
1545     const bool isScalable = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_SCALABLE ) );
1546     const bool hasFixedSizedBitmaps = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_FIXED_SIZES ) ) && ( 0 != ftFace->num_fixed_sizes );
1547     const bool hasColorTables = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_COLOR ) );
1548
1549     DALI_LOG_INFO( gLogFilter, Debug::General, "            isScalable : [%s]\n", ( isScalable ? "true" : "false" ) );
1550     DALI_LOG_INFO( gLogFilter, Debug::General, "  hasFixedSizedBitmaps : [%s]\n", ( hasFixedSizedBitmaps ? "true" : "false" ) );
1551     DALI_LOG_INFO( gLogFilter, Debug::General, "        hasColorTables : [%s]\n", ( hasColorTables ? "true" : "false" ) );
1552
1553     // Check to see if the font contains fixed sizes?
1554     if( !isScalable && hasFixedSizedBitmaps )
1555     {
1556       PointSize26Dot6 actualPointSize = 0u;
1557       int fixedSizeIndex = 0;
1558       for( ; fixedSizeIndex < ftFace->num_fixed_sizes; ++fixedSizeIndex )
1559       {
1560         const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size;
1561         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  size index : %d, size : %d\n", fixedSizeIndex, fixedSize );
1562
1563         if( fixedSize >= requestedPointSize )
1564         {
1565           actualPointSize = fixedSize;
1566           break;
1567         }
1568       }
1569
1570       if( 0u == actualPointSize )
1571       {
1572         // The requested point size is bigger than the bigest fixed size.
1573         fixedSizeIndex = ftFace->num_fixed_sizes - 1;
1574         actualPointSize = ftFace->available_sizes[fixedSizeIndex].size;
1575       }
1576
1577       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize );
1578
1579       // Tell Freetype to use this size
1580       error = FT_Select_Size( ftFace, fixedSizeIndex );
1581       if ( FT_Err_Ok != error )
1582       {
1583         DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Select_Size error: %d\n", error );
1584       }
1585       else
1586       {
1587         float fixedWidth  = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].width );
1588         float fixedHeight = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].height );
1589
1590         // Indicate that the font is a fixed sized bitmap
1591         FontMetrics metrics( fixedHeight, // The ascender in pixels.
1592                              0.0f,
1593                              fixedHeight, // The height in pixels.
1594                              0.0f,
1595                              0.0f );
1596
1597         mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedWidth, fixedHeight, hasColorTables ) );
1598         id = mFontCache.size();
1599       }
1600     }
1601     else
1602     {
1603       error = FT_Set_Char_Size( ftFace,
1604                                 0,
1605                                 requestedPointSize,
1606                                 mDpiHorizontal,
1607                                 mDpiVertical );
1608
1609       if( FT_Err_Ok == error )
1610       {
1611
1612         FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1613
1614         FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
1615                              static_cast< float >( ftMetrics.descender ) * FROM_266,
1616                              static_cast< float >( ftMetrics.height    ) * FROM_266,
1617                              static_cast< float >( ftFace->underline_position ) * FROM_266,
1618                              static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1619
1620         mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics ) );
1621         id = mFontCache.size();
1622       }
1623       else
1624       {
1625         DALI_LOG_INFO( gLogFilter, Debug::General, "  FreeType Set_Char_Size error: %d for pointSize %d\n", error, requestedPointSize );
1626       }
1627     }
1628
1629     if( 0u != id )
1630     {
1631       if( cacheDescription )
1632       {
1633         CacheFontPath( ftFace, id, requestedPointSize, path );
1634       }
1635     }
1636   }
1637   else
1638   {
1639     DALI_LOG_INFO( gLogFilter, Debug::General, "  FreeType New_Face error: %d for [%s]\n", error, path.c_str() );
1640   }
1641
1642   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
1643   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::CreateFont\n" );
1644
1645   return id;
1646 }
1647
1648 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap )
1649 {
1650   if( srcBitmap.width*srcBitmap.rows > 0 )
1651   {
1652     switch( srcBitmap.pixel_mode )
1653     {
1654       case FT_PIXEL_MODE_GRAY:
1655       {
1656         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
1657         {
1658           const unsigned int bufferSize = srcBitmap.width * srcBitmap.rows;
1659           data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1660           data.width = srcBitmap.width;
1661           data.height = srcBitmap.rows;
1662           data.format = Pixel::L8;
1663           memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1664         }
1665         break;
1666       }
1667
1668 #ifdef FREETYPE_BITMAP_SUPPORT
1669       case FT_PIXEL_MODE_BGRA:
1670       {
1671         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
1672         {
1673           // Set the input dimensions.
1674           const ImageDimensions inputDimensions( srcBitmap.width, srcBitmap.rows );
1675
1676           // Set the output dimensions.
1677           // If the output dimension is not given, the input dimension is set
1678           // and won't be downscaling.
1679           data.width = ( data.width == 0 ) ? srcBitmap.width : data.width;
1680           data.height = ( data.height == 0 ) ? srcBitmap.rows : data.height;
1681           const ImageDimensions desiredDimensions( data.width, data.height );
1682
1683           // Creates the output buffer
1684           const unsigned int bufferSize = data.width * data.height * 4u;
1685           data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1686
1687           if( inputDimensions == desiredDimensions )
1688           {
1689             // There isn't downscaling.
1690             memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1691           }
1692           else
1693           {
1694             Dali::Internal::Platform::LanczosSample4BPP( srcBitmap.buffer,
1695                                                          inputDimensions,
1696                                                          data.buffer,
1697                                                          desiredDimensions );
1698           }
1699           data.format = Pixel::BGRA8888;
1700         }
1701         break;
1702       }
1703 #endif
1704       default:
1705       {
1706         DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::ConvertBitmap. FontClient Unable to create Bitmap of this PixelType\n" );
1707         break;
1708       }
1709     }
1710   }
1711 }
1712
1713 bool FontClient::Plugin::FindFont( const FontPath& path,
1714                                    PointSize26Dot6 requestedPointSize,
1715                                    FaceIndex faceIndex,
1716                                    FontId& fontId ) const
1717 {
1718   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
1719   DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
1720   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1721   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of fonts in the cache : %d\n", mFontCache.size() );
1722
1723   fontId = 0u;
1724   for( std::vector<FontFaceCacheItem>::const_iterator it = mFontCache.begin(),
1725          endIt = mFontCache.end();
1726        it != endIt;
1727        ++it, ++fontId )
1728   {
1729     const FontFaceCacheItem& cacheItem = *it;
1730
1731     if( cacheItem.mRequestedPointSize == requestedPointSize &&
1732         cacheItem.mFaceIndex == faceIndex &&
1733         cacheItem.mPath == path )
1734     {
1735       ++fontId;
1736
1737       DALI_LOG_INFO( gLogFilter, Debug::General, "  font found, id : %d\n", fontId );
1738       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1739
1740       return true;
1741     }
1742   }
1743
1744   DALI_LOG_INFO( gLogFilter, Debug::General, "  font not found\n" );
1745   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1746
1747   return false;
1748 }
1749
1750 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1751                                             FontDescriptionId& validatedFontId )
1752 {
1753   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindValidatedFont\n" );
1754   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1755   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1756   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1757   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1758   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1759   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of validated fonts in the cache : %d\n", mValidatedFontCache.size() );
1760
1761   validatedFontId = 0u;
1762
1763   for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
1764          endIt = mValidatedFontCache.end();
1765        it != endIt;
1766        ++it )
1767   {
1768     const FontDescriptionCacheItem& item = *it;
1769
1770     if( !fontDescription.family.empty() &&
1771         ( fontDescription.family == item.fontDescription.family ) &&
1772         ( fontDescription.width == item.fontDescription.width ) &&
1773         ( fontDescription.weight == item.fontDescription.weight ) &&
1774         ( fontDescription.slant == item.fontDescription.slant ) )
1775     {
1776       validatedFontId = item.index;
1777
1778       DALI_LOG_INFO( gLogFilter, Debug::General, "  validated font found, id : %d\n", validatedFontId );
1779       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
1780       return true;
1781     }
1782   }
1783
1784   DALI_LOG_INFO( gLogFilter, Debug::General, "  validated font not found\n" );
1785   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
1786   return false;
1787 }
1788
1789 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
1790                                                FontList*& fontList,
1791                                                CharacterSetList*& characterSetList )
1792 {
1793   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFontList\n" );
1794   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1795   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1796   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1797   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1798   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1799   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of fallback font lists in the cache : %d\n", mFallbackCache.size() );
1800
1801   fontList = NULL;
1802
1803   for( std::vector<FallbackCacheItem>::const_iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
1804        it != endIt;
1805        ++it )
1806   {
1807     const FallbackCacheItem& item = *it;
1808
1809     if( !fontDescription.family.empty() &&
1810         ( fontDescription.family == item.fontDescription.family ) &&
1811         ( fontDescription.width == item.fontDescription.width ) &&
1812         ( fontDescription.weight == item.fontDescription.weight ) &&
1813         ( fontDescription.slant == item.fontDescription.slant ) )
1814     {
1815       fontList = item.fallbackFonts;
1816       characterSetList = item.characterSets;
1817
1818       DALI_LOG_INFO( gLogFilter, Debug::General, "  fallback font list found.\n" );
1819       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
1820       return true;
1821     }
1822   }
1823
1824   DALI_LOG_INFO( gLogFilter, Debug::General, "  fallback font list not found.\n" );
1825   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
1826   return false;
1827 }
1828
1829 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1830                                    PointSize26Dot6 requestedPointSize,
1831                                    FontId& fontId )
1832 {
1833   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
1834   DALI_LOG_INFO( gLogFilter, Debug::General, "    validatedFontId  : %d\n", validatedFontId );
1835   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1836
1837   fontId = 0u;
1838
1839   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
1840          endIt = mFontIdCache.end();
1841        it != endIt;
1842        ++it )
1843   {
1844     const FontIdCacheItem& item = *it;
1845
1846     if( ( validatedFontId == item.validatedFontId ) &&
1847         ( requestedPointSize == item.requestedPointSize ) )
1848     {
1849       fontId = item.fontId;
1850
1851       DALI_LOG_INFO( gLogFilter, Debug::General, "  font found, id : %d\n", fontId );
1852       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1853       return true;
1854     }
1855   }
1856
1857   DALI_LOG_INFO( gLogFilter, Debug::General, "  font not found.\n" );
1858   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1859   return false;
1860 }
1861
1862 bool FontClient::Plugin::IsScalable( const FontPath& path )
1863 {
1864   bool isScalable = false;
1865
1866   FT_Face ftFace;
1867   int error = FT_New_Face( mFreeTypeLibrary,
1868                            path.c_str(),
1869                            0,
1870                            &ftFace );
1871   if( FT_Err_Ok != error )
1872   {
1873     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: %s\n", path.c_str() );
1874   }
1875   else
1876   {
1877     isScalable = ftFace->face_flags & FT_FACE_FLAG_SCALABLE;
1878   }
1879
1880   return isScalable;
1881 }
1882
1883 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1884 {
1885   // Create a font pattern.
1886   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1887
1888   FcResult result = FcResultMatch;
1889
1890   // match the pattern
1891   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1892   bool isScalable = false;
1893
1894   if( match )
1895   {
1896     // Get the path to the font file name.
1897     FontPath path;
1898     GetFcString( match, FC_FILE, path );
1899     isScalable = IsScalable( path );
1900   }
1901   else
1902   {
1903     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
1904   }
1905   FcPatternDestroy( fontFamilyPattern );
1906   FcPatternDestroy( match );
1907   return isScalable;
1908 }
1909
1910 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1911 {
1912   // Empty the caller container
1913   sizes.Clear();
1914
1915   FT_Face ftFace;
1916   int error = FT_New_Face( mFreeTypeLibrary,
1917                            path.c_str(),
1918                            0,
1919                            &ftFace );
1920   if( FT_Err_Ok != error )
1921   {
1922     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font path : [%s]\n", path.c_str() );
1923   }
1924
1925   // Fetch the number of fixed sizes available
1926   if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1927   {
1928     for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1929     {
1930       sizes.PushBack( ftFace->available_sizes[ i ].size );
1931     }
1932   }
1933 }
1934
1935 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1936                                         Vector< PointSize26Dot6 >& sizes )
1937 {
1938   // Create a font pattern.
1939   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1940
1941   FcResult result = FcResultMatch;
1942
1943   // match the pattern
1944   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1945
1946   if( match )
1947   {
1948     // Get the path to the font file name.
1949     FontPath path;
1950     GetFcString( match, FC_FILE, path );
1951     GetFixedSizes( path, sizes );
1952   }
1953   else
1954   {
1955     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
1956   }
1957   FcPatternDestroy( match );
1958   FcPatternDestroy( fontFamilyPattern );
1959 }
1960
1961 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize,  const FontPath& path )
1962 {
1963   FontDescription description;
1964   description.path = path;
1965   description.family = FontFamily( ftFace->family_name );
1966   description.weight = FontWeight::NONE;
1967   description.width = FontWidth::NONE;
1968   description.slant = FontSlant::NONE;
1969
1970   // Note FreeType doesn't give too much info to build a proper font style.
1971   if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1972   {
1973     description.slant = FontSlant::ITALIC;
1974   }
1975   if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1976   {
1977     description.weight = FontWeight::BOLD;
1978   }
1979
1980   FontDescriptionId validatedFontId = 0u;
1981   if( !FindValidatedFont( description,
1982                           validatedFontId ) )
1983   {
1984     // Set the index to the vector of paths to font file names.
1985     validatedFontId = mFontDescriptionCache.size();
1986
1987     FcPattern* pattern = CreateFontFamilyPattern( description );
1988
1989     FcResult result = FcResultMatch;
1990     FcPattern* match = FcFontMatch( NULL, pattern, &result );
1991
1992     FcCharSet* characterSet = NULL;
1993     FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
1994
1995     FcPatternDestroy( pattern );
1996
1997     mMatchedFcPatternCache.PushBack( match );
1998
1999     mFontCache[id-1u].mCharacterSet = characterSet;
2000
2001     // Add the path to the cache.
2002     mFontDescriptionCache.push_back( description );
2003     mCharacterSetCache.PushBack( characterSet );
2004
2005     // Cache the index and the font's description.
2006     FontDescriptionCacheItem item( description,
2007                                    validatedFontId );
2008
2009     mValidatedFontCache.push_back( item );
2010
2011     // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
2012     mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
2013                                              requestedPointSize,
2014                                              id ) );
2015   }
2016 }
2017
2018 FcCharSet* FontClient::Plugin::CreateCharacterSetFromDescription( const FontDescription& description )
2019 {
2020   FcCharSet* characterSet = NULL;
2021
2022   FcPattern* pattern = CreateFontFamilyPattern( description );
2023
2024   if( NULL != pattern )
2025   {
2026     FcResult result = FcResultMatch;
2027     FcPattern* match = FcFontMatch( NULL, pattern, &result );
2028
2029     FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
2030
2031     mMatchedFcPatternCache.PushBack( match );
2032
2033     FcPatternDestroy( pattern );
2034   }
2035
2036   return characterSet;
2037 }
2038
2039 void FontClient::Plugin::DestroyMatchedPatterns()
2040 {
2041   for (auto & object : mMatchedFcPatternCache) {
2042     FcPatternDestroy(reinterpret_cast<FcPattern*>(object));
2043   }
2044   mMatchedFcPatternCache.Clear();
2045 }
2046
2047 } // namespace Internal
2048
2049 } // namespace TextAbstraction
2050
2051 } // namespace Dali