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