Revert "[Tizen] Support custom fonts registration"
[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 void FontClient::Plugin::InitSystemFonts()
1260 {
1261   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::InitSystemFonts\n" );
1262
1263   FcFontSet* fontSet = GetFcFontSet();
1264
1265   if( fontSet )
1266   {
1267     DALI_LOG_INFO( gLogFilter, Debug::General, "  number of system fonts : %d\n", fontSet->nfont );
1268
1269     // Reserve some space to avoid reallocations.
1270     mSystemFonts.reserve( fontSet->nfont );
1271
1272     for( int i = 0u; i < fontSet->nfont; ++i )
1273     {
1274       FcPattern* fontPattern = fontSet->fonts[i];
1275
1276       FontPath path;
1277
1278       // Skip fonts with no path
1279       if( GetFcString( fontPattern, FC_FILE, path ) )
1280       {
1281         mSystemFonts.push_back( FontDescription() );
1282         FontDescription& fontDescription = mSystemFonts.back();
1283
1284         fontDescription.path = std::move( path );
1285
1286         int width = 0;
1287         int weight = 0;
1288         int slant = 0;
1289         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
1290         GetFcInt( fontPattern, FC_WIDTH, width );
1291         GetFcInt( fontPattern, FC_WEIGHT, weight );
1292         GetFcInt( fontPattern, FC_SLANT, slant );
1293         fontDescription.width = IntToWidthType( width );
1294         fontDescription.weight = IntToWeightType( weight );
1295         fontDescription.slant = IntToSlantType( slant );
1296
1297         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  description; family : [%s]\n", fontDescription.family.c_str() );
1298         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1299         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1300         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1301         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1302       }
1303     }
1304
1305     FcFontSetDestroy( fontSet );
1306   }
1307   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::InitSystemFonts\n" );
1308 }
1309
1310 bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet )
1311 {
1312   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1313
1314   FcResult result = FcResultMatch;
1315   FcPattern* match = FcFontMatch( nullptr /* use default configure */, pattern, &result );
1316
1317   const bool matched = nullptr != match;
1318   DALI_LOG_INFO( gLogFilter, Debug::General, "  pattern matched : %s\n", ( matched ? "true" : "false" ) );
1319
1320   if( matched )
1321   {
1322     int width = 0;
1323     int weight = 0;
1324     int slant = 0;
1325     GetFcString( match, FC_FILE, fontDescription.path );
1326     GetFcString( match, FC_FAMILY, fontDescription.family );
1327     GetFcInt( match, FC_WIDTH, width );
1328     GetFcInt( match, FC_WEIGHT, weight );
1329     GetFcInt( match, FC_SLANT, slant );
1330     fontDescription.width = IntToWidthType( width );
1331     fontDescription.weight = IntToWeightType( weight );
1332     fontDescription.slant = IntToSlantType( slant );
1333
1334     // Cache the character ranges.
1335     FcPatternGetCharSet( match, FC_CHARSET, 0u, characterSet );
1336
1337     // destroyed the matched pattern
1338     FcPatternDestroy( match );
1339
1340     DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1341     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1342     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1343     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1344     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1345   }
1346
1347   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1348   return matched;
1349 }
1350
1351 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription ) const
1352 {
1353   // create the cached font family lookup pattern
1354   // a pattern holds a set of names, each name refers to a property of the font
1355   FcPattern* fontFamilyPattern = FcPatternCreate();
1356
1357   if( !fontFamilyPattern )
1358   {
1359     return nullptr;
1360   }
1361
1362   // add a property to the pattern for the font family
1363   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
1364
1365   int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
1366   if( width < 0 )
1367   {
1368     // Use default.
1369     width = DEFAULT_FONT_WIDTH;
1370   }
1371
1372   int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
1373   if( weight < 0 )
1374   {
1375     // Use default.
1376     weight = DEFAULT_FONT_WEIGHT;
1377   }
1378
1379   int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
1380   if( slant < 0 )
1381   {
1382     // Use default.
1383     slant = DEFAULT_FONT_SLANT;
1384   }
1385
1386   FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
1387   FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
1388   FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
1389
1390   // Add a property of the pattern, to say we want to match TrueType fonts
1391   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
1392
1393   // modify the config, with the mFontFamilyPatterm
1394   FcConfigSubstitute( nullptr /* use default configure */, fontFamilyPattern, FcMatchPattern );
1395
1396   // provide default values for unspecified properties in the font pattern
1397   // e.g. patterns without a specified style or weight are set to Medium
1398   FcDefaultSubstitute( fontFamilyPattern );
1399
1400   return fontFamilyPattern;
1401 }
1402
1403 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
1404 {
1405   // create a new pattern.
1406   // a pattern holds a set of names, each name refers to a property of the font
1407   FcPattern* pattern = FcPatternCreate();
1408
1409   FcFontSet* fontset = NULL;
1410
1411   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
1412   FcObjectSet* objectSet = FcObjectSetCreate();
1413
1414   if( objectSet )
1415   {
1416     // build an object set from a list of property names
1417     FcObjectSetAdd( objectSet, FC_FILE );
1418     FcObjectSetAdd( objectSet, FC_FAMILY );
1419     FcObjectSetAdd( objectSet, FC_WIDTH );
1420     FcObjectSetAdd( objectSet, FC_WEIGHT );
1421     FcObjectSetAdd( objectSet, FC_SLANT );
1422
1423     // get a list of fonts
1424     // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
1425     fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
1426
1427     // clear up the object set
1428     FcObjectSetDestroy( objectSet );
1429   }
1430   // clear up the pattern
1431   if( pattern )
1432   {
1433     FcPatternDestroy( pattern );
1434   }
1435
1436   return fontset;
1437 }
1438
1439 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1440                                       const char* const n,
1441                                       std::string& string )
1442 {
1443   FcChar8* file = nullptr;
1444   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1445
1446   if( FcResultMatch == retVal )
1447   {
1448     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1449     string.assign( reinterpret_cast<const char*>( file ) );
1450
1451     return true;
1452   }
1453
1454   return false;
1455 }
1456
1457 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
1458 {
1459   const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
1460
1461   if( FcResultMatch == retVal )
1462   {
1463     return true;
1464   }
1465
1466   return false;
1467 }
1468
1469 FontId FontClient::Plugin::CreateFont( const FontPath& path,
1470                                        PointSize26Dot6 requestedPointSize,
1471                                        FaceIndex faceIndex,
1472                                        bool cacheDescription )
1473 {
1474   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::CreateFont\n" );
1475   DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
1476   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1477
1478   FontId id = 0u;
1479
1480   // Create & cache new font face
1481   FT_Face ftFace;
1482   int error = FT_New_Face( mFreeTypeLibrary,
1483                            path.c_str(),
1484                            0,
1485                            &ftFace );
1486
1487   if( FT_Err_Ok == error )
1488   {
1489     // Check if a font is scalable.
1490     const bool isScalable = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_SCALABLE ) );
1491     const bool hasFixedSizedBitmaps = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_FIXED_SIZES ) ) && ( 0 != ftFace->num_fixed_sizes );
1492     const bool hasColorTables = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_COLOR ) );
1493
1494     DALI_LOG_INFO( gLogFilter, Debug::General, "            isScalable : [%s]\n", ( isScalable ? "true" : "false" ) );
1495     DALI_LOG_INFO( gLogFilter, Debug::General, "  hasFixedSizedBitmaps : [%s]\n", ( hasFixedSizedBitmaps ? "true" : "false" ) );
1496     DALI_LOG_INFO( gLogFilter, Debug::General, "        hasColorTables : [%s]\n", ( hasColorTables ? "true" : "false" ) );
1497
1498     // Check to see if the font contains fixed sizes?
1499     if( !isScalable && hasFixedSizedBitmaps )
1500     {
1501       PointSize26Dot6 actualPointSize = 0u;
1502       int fixedSizeIndex = 0;
1503       for( ; fixedSizeIndex < ftFace->num_fixed_sizes; ++fixedSizeIndex )
1504       {
1505         const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size;
1506         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  size index : %d, size : %d\n", fixedSizeIndex, fixedSize );
1507
1508         if( fixedSize >= requestedPointSize )
1509         {
1510           actualPointSize = fixedSize;
1511           break;
1512         }
1513       }
1514
1515       if( 0u == actualPointSize )
1516       {
1517         // The requested point size is bigger than the bigest fixed size.
1518         fixedSizeIndex = ftFace->num_fixed_sizes - 1;
1519         actualPointSize = ftFace->available_sizes[fixedSizeIndex].size;
1520       }
1521
1522       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize );
1523
1524       // Tell Freetype to use this size
1525       error = FT_Select_Size( ftFace, fixedSizeIndex );
1526       if ( FT_Err_Ok != error )
1527       {
1528         DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Select_Size error: %d\n", error );
1529       }
1530       else
1531       {
1532         float fixedWidth  = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].width );
1533         float fixedHeight = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].height );
1534
1535         // Indicate that the font is a fixed sized bitmap
1536         FontMetrics metrics( fixedHeight, // The ascender in pixels.
1537                              0.0f,
1538                              fixedHeight, // The height in pixels.
1539                              0.0f,
1540                              0.0f );
1541
1542         mFontFaceCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedWidth, fixedHeight, hasColorTables ) );
1543         id = mFontFaceCache.size();
1544       }
1545     }
1546     else
1547     {
1548       error = FT_Set_Char_Size( ftFace,
1549                                 0,
1550                                 requestedPointSize,
1551                                 mDpiHorizontal,
1552                                 mDpiVertical );
1553
1554       if( FT_Err_Ok == error )
1555       {
1556
1557         FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1558
1559         FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
1560                              static_cast< float >( ftMetrics.descender ) * FROM_266,
1561                              static_cast< float >( ftMetrics.height    ) * FROM_266,
1562                              static_cast< float >( ftFace->underline_position ) * FROM_266,
1563                              static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1564
1565         mFontFaceCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics ) );
1566         id = mFontFaceCache.size();
1567       }
1568       else
1569       {
1570         DALI_LOG_INFO( gLogFilter, Debug::General, "  FreeType Set_Char_Size error: %d for pointSize %d\n", error, requestedPointSize );
1571       }
1572     }
1573
1574     if( 0u != id )
1575     {
1576       if( cacheDescription )
1577       {
1578         CacheFontPath( ftFace, id, requestedPointSize, path );
1579       }
1580     }
1581   }
1582   else
1583   {
1584     DALI_LOG_INFO( gLogFilter, Debug::General, "  FreeType New_Face error: %d for [%s]\n", error, path.c_str() );
1585   }
1586
1587   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
1588   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::CreateFont\n" );
1589
1590   return id;
1591 }
1592
1593 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap )
1594 {
1595   if( srcBitmap.width*srcBitmap.rows > 0 )
1596   {
1597     switch( srcBitmap.pixel_mode )
1598     {
1599       case FT_PIXEL_MODE_GRAY:
1600       {
1601         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
1602         {
1603           const unsigned int bufferSize = srcBitmap.width * srcBitmap.rows;
1604           data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1605           data.width = srcBitmap.width;
1606           data.height = srcBitmap.rows;
1607           data.format = Pixel::L8;
1608           memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1609         }
1610         break;
1611       }
1612
1613 #ifdef FREETYPE_BITMAP_SUPPORT
1614       case FT_PIXEL_MODE_BGRA:
1615       {
1616         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
1617         {
1618           // Set the input dimensions.
1619           const ImageDimensions inputDimensions( srcBitmap.width, srcBitmap.rows );
1620
1621           // Set the output dimensions.
1622           // If the output dimension is not given, the input dimension is set
1623           // and won't be downscaling.
1624           data.width = ( data.width == 0 ) ? srcBitmap.width : data.width;
1625           data.height = ( data.height == 0 ) ? srcBitmap.rows : data.height;
1626           const ImageDimensions desiredDimensions( data.width, data.height );
1627
1628           // Creates the output buffer
1629           const unsigned int bufferSize = data.width * data.height * 4u;
1630           data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1631
1632           if( inputDimensions == desiredDimensions )
1633           {
1634             // There isn't downscaling.
1635             memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1636           }
1637           else
1638           {
1639             Dali::Internal::Platform::LanczosSample4BPP( srcBitmap.buffer,
1640                                                          inputDimensions,
1641                                                          data.buffer,
1642                                                          desiredDimensions );
1643           }
1644           data.format = Pixel::BGRA8888;
1645         }
1646         break;
1647       }
1648 #endif
1649       default:
1650       {
1651         DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::ConvertBitmap. FontClient Unable to create Bitmap of this PixelType\n" );
1652         break;
1653       }
1654     }
1655   }
1656 }
1657
1658 bool FontClient::Plugin::FindFont( const FontPath& path,
1659                                    PointSize26Dot6 requestedPointSize,
1660                                    FaceIndex faceIndex,
1661                                    FontId& fontId ) const
1662 {
1663   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
1664   DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
1665   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1666   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of fonts in the cache : %d\n", mFontFaceCache.size() );
1667
1668   fontId = 0u;
1669   for( const auto& cacheItem : mFontFaceCache )
1670   {
1671     ++fontId;
1672     if( cacheItem.mRequestedPointSize == requestedPointSize &&
1673         cacheItem.mFaceIndex == faceIndex &&
1674         cacheItem.mPath == path )
1675     {
1676
1677       DALI_LOG_INFO( gLogFilter, Debug::General, "  font found, id : %d\n", fontId );
1678       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1679
1680       return true;
1681     }
1682   }
1683
1684   DALI_LOG_INFO( gLogFilter, Debug::General, "  font not found\n" );
1685   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1686
1687   fontId = 0u;
1688   return false;
1689 }
1690
1691 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1692                                             FontDescriptionId& validatedFontId )
1693 {
1694   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindValidatedFont\n" );
1695   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1696   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1697   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1698   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1699   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1700   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of validated fonts in the cache : %d\n", mValidatedFontCache.size() );
1701
1702   validatedFontId = 0u;
1703
1704   for( const auto& item : mValidatedFontCache )
1705   {
1706     if( !fontDescription.family.empty() &&
1707         ( fontDescription.family == item.fontDescription.family ) &&
1708         ( fontDescription.width == item.fontDescription.width ) &&
1709         ( fontDescription.weight == item.fontDescription.weight ) &&
1710         ( fontDescription.slant == item.fontDescription.slant ) )
1711     {
1712       validatedFontId = item.index;
1713
1714       DALI_LOG_INFO( gLogFilter, Debug::General, "  validated font found, id : %d\n", validatedFontId );
1715       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
1716       return true;
1717     }
1718   }
1719
1720   DALI_LOG_INFO( gLogFilter, Debug::General, "  validated font not found\n" );
1721   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
1722   return false;
1723 }
1724
1725 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
1726                                                FontList*& fontList,
1727                                                CharacterSetList*& characterSetList )
1728 {
1729   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFontList\n" );
1730   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1731   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1732   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1733   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1734   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1735   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of fallback font lists in the cache : %d\n", mFallbackCache.size() );
1736
1737   fontList = nullptr;
1738
1739   for( const auto& item : mFallbackCache )
1740   {
1741     if( !fontDescription.family.empty() &&
1742         ( fontDescription.family == item.fontDescription.family ) &&
1743         ( fontDescription.width == item.fontDescription.width ) &&
1744         ( fontDescription.weight == item.fontDescription.weight ) &&
1745         ( fontDescription.slant == item.fontDescription.slant ) )
1746     {
1747       fontList = item.fallbackFonts;
1748       characterSetList = item.characterSets;
1749
1750       DALI_LOG_INFO( gLogFilter, Debug::General, "  fallback font list found.\n" );
1751       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
1752       return true;
1753     }
1754   }
1755
1756   DALI_LOG_INFO( gLogFilter, Debug::General, "  fallback font list not found.\n" );
1757   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
1758   return false;
1759 }
1760
1761 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1762                                    PointSize26Dot6 requestedPointSize,
1763                                    FontId& fontId )
1764 {
1765   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
1766   DALI_LOG_INFO( gLogFilter, Debug::General, "    validatedFontId  : %d\n", validatedFontId );
1767   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1768
1769   fontId = 0u;
1770
1771   for( const auto& item : mFontDescriptionSizeCache )
1772   {
1773     if( ( validatedFontId == item.validatedFontId ) &&
1774         ( requestedPointSize == item.requestedPointSize ) )
1775     {
1776       fontId = item.fontId;
1777
1778       DALI_LOG_INFO( gLogFilter, Debug::General, "  font found, id : %d\n", fontId );
1779       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1780       return true;
1781     }
1782   }
1783
1784   DALI_LOG_INFO( gLogFilter, Debug::General, "  font not found.\n" );
1785   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1786   return false;
1787 }
1788
1789 bool FontClient::Plugin::IsScalable( const FontPath& path )
1790 {
1791   bool isScalable = false;
1792
1793   FT_Face ftFace;
1794   int error = FT_New_Face( mFreeTypeLibrary,
1795                            path.c_str(),
1796                            0,
1797                            &ftFace );
1798   if( FT_Err_Ok != error )
1799   {
1800     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: %s\n", path.c_str() );
1801   }
1802   else
1803   {
1804     isScalable = ftFace->face_flags & FT_FACE_FLAG_SCALABLE;
1805   }
1806
1807   return isScalable;
1808 }
1809
1810 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1811 {
1812   // Create a font pattern.
1813   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1814
1815   FcResult result = FcResultMatch;
1816
1817   // match the pattern
1818   FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result );
1819   bool isScalable = false;
1820
1821   if( match )
1822   {
1823     // Get the path to the font file name.
1824     FontPath path;
1825     GetFcString( match, FC_FILE, path );
1826     isScalable = IsScalable( path );
1827   }
1828   else
1829   {
1830     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
1831   }
1832   FcPatternDestroy( fontFamilyPattern );
1833   FcPatternDestroy( match );
1834   return isScalable;
1835 }
1836
1837 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1838 {
1839   // Empty the caller container
1840   sizes.Clear();
1841
1842   FT_Face ftFace;
1843   int error = FT_New_Face( mFreeTypeLibrary,
1844                            path.c_str(),
1845                            0,
1846                            &ftFace );
1847   if( FT_Err_Ok != error )
1848   {
1849     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font path : [%s]\n", path.c_str() );
1850   }
1851
1852   // Fetch the number of fixed sizes available
1853   if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1854   {
1855     for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1856     {
1857       sizes.PushBack( ftFace->available_sizes[ i ].size );
1858     }
1859   }
1860 }
1861
1862 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1863                                         Vector< PointSize26Dot6 >& sizes )
1864 {
1865   // Create a font pattern.
1866   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1867
1868   FcResult result = FcResultMatch;
1869
1870   // match the pattern
1871   FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result );
1872
1873   if( match )
1874   {
1875     // Get the path to the font file name.
1876     FontPath path;
1877     GetFcString( match, FC_FILE, path );
1878     GetFixedSizes( path, sizes );
1879   }
1880   else
1881   {
1882     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
1883   }
1884   FcPatternDestroy( match );
1885   FcPatternDestroy( fontFamilyPattern );
1886 }
1887
1888 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize,  const FontPath& path )
1889 {
1890   FontDescription description;
1891   description.path = path;
1892   description.family = std::move( FontFamily( ftFace->family_name ) );
1893   description.weight = FontWeight::NONE;
1894   description.width = FontWidth::NONE;
1895   description.slant = FontSlant::NONE;
1896
1897   // Note FreeType doesn't give too much info to build a proper font style.
1898   if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1899   {
1900     description.slant = FontSlant::ITALIC;
1901   }
1902   if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1903   {
1904     description.weight = FontWeight::BOLD;
1905   }
1906
1907   FontDescriptionId validatedFontId = 0u;
1908   if( !FindValidatedFont( description,
1909                           validatedFontId ) )
1910   {
1911     // Set the index to the vector of paths to font file names.
1912     validatedFontId = mFontDescriptionCache.size();
1913
1914     FcPattern* pattern = CreateFontFamilyPattern( description );
1915
1916     FcResult result = FcResultMatch;
1917     FcPattern* match = FcFontMatch( nullptr, pattern, &result );
1918
1919     FcCharSet* characterSet = nullptr;
1920     FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
1921
1922     FcPatternDestroy( pattern );
1923
1924     mMatchedFcPatternCache.PushBack( match );
1925
1926     mFontFaceCache[id-1u].mCharacterSet = characterSet;
1927
1928     // Add the path to the cache.
1929     mFontDescriptionCache.push_back( description );
1930     mCharacterSetCache.PushBack( characterSet );
1931
1932     // Cache the index and the font's description.
1933     mValidatedFontCache.push_back( std::move( FontDescriptionCacheItem( std::move( description ),
1934                                                                         validatedFontId) ) );
1935
1936     // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
1937     mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId,
1938                                                                        requestedPointSize,
1939                                                                        id ) );
1940   }
1941 }
1942
1943 FcCharSet* FontClient::Plugin::CreateCharacterSetFromDescription( const FontDescription& description )
1944 {
1945   FcCharSet* characterSet = nullptr;
1946
1947   FcPattern* pattern = CreateFontFamilyPattern( description );
1948
1949   if( nullptr != pattern )
1950   {
1951     FcResult result = FcResultMatch;
1952     FcPattern* match = FcFontMatch( nullptr, pattern, &result );
1953
1954     FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
1955     mMatchedFcPatternCache.PushBack( match );
1956
1957     FcPatternDestroy( pattern );
1958   }
1959
1960   return characterSet;
1961 }
1962
1963 void FontClient::Plugin::DestroyMatchedPatterns()
1964 {
1965   for (auto & object : mMatchedFcPatternCache)
1966   {
1967     FcPatternDestroy(reinterpret_cast<FcPattern*>(object));
1968   }
1969   mMatchedFcPatternCache.Clear();
1970 }
1971
1972 } // namespace Internal
1973
1974 } // namespace TextAbstraction
1975
1976 } // namespace Dali