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