FontConfig - Remove the font format from the match pattern.
[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 #include <dali/devel-api/adaptor-framework/image-loading.h>
31
32 // EXTERNAL INCLUDES
33 #include <fontconfig/fontconfig.h>
34
35 namespace
36 {
37
38 #if defined(DEBUG_ENABLED)
39 Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
40 #endif
41
42 /**
43  * Conversion from Fractional26.6 to float
44  */
45 const float FROM_266 = 1.0f / 64.0f;
46 const float POINTS_PER_INCH = 72.f;
47
48 const std::string 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 /**
142  * @brief Free the resources allocated by the FcCharSet objects.
143  *
144  * @param[in] characterSets The vector of character sets.
145  */
146 void DestroyCharacterSets( CharacterSetList& characterSets )
147 {
148   for( auto& item : characterSets )
149   {
150     FcCharSetDestroy( item );
151   }
152 }
153
154 FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( FontDescription&& font, FontList* fallbackFonts, CharacterSetList* characterSets )
155 : fontDescription{ std::move( font ) },
156   fallbackFonts{ fallbackFonts },
157   characterSets{ characterSets }
158 {
159 }
160
161 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
162                                                                         FontDescriptionId index )
163 : fontDescription{ fontDescription },
164   index{ index }
165 {
166 }
167
168 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( FontDescription&& fontDescription,
169                                                                         FontDescriptionId index )
170 : fontDescription{ std::move( fontDescription ) },
171   index{ index }
172 {
173 }
174
175 FontClient::Plugin::FontDescriptionSizeCacheItem::FontDescriptionSizeCacheItem( FontDescriptionId validatedFontId,
176                                                                                 PointSize26Dot6 requestedPointSize,
177                                                                                 FontId fontId )
178 : validatedFontId( validatedFontId ),
179   requestedPointSize( requestedPointSize ),
180   fontId( fontId )
181 {
182 }
183
184 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
185                                                           const FontPath& path,
186                                                           PointSize26Dot6 requestedPointSize,
187                                                           FaceIndex face,
188                                                           const FontMetrics& metrics )
189 : mFreeTypeFace( ftFace ),
190   mPath( path ),
191   mRequestedPointSize( requestedPointSize ),
192   mFaceIndex( face ),
193   mMetrics( metrics ),
194   mCharacterSet( nullptr ),
195   mFixedSizeIndex( 0 ),
196   mFixedWidthPixels( 0.f ),
197   mFixedHeightPixels( 0.f ),
198   mVectorFontId( 0u ),
199   mFontId( 0u ),
200   mIsFixedSizeBitmap( false ),
201   mHasColorTables( false )
202 {
203 }
204
205 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
206                                                           const FontPath& path,
207                                                           PointSize26Dot6 requestedPointSize,
208                                                           FaceIndex face,
209                                                           const FontMetrics& metrics,
210                                                           int fixedSizeIndex,
211                                                           float fixedWidth,
212                                                           float fixedHeight,
213                                                           bool hasColorTables )
214 : mFreeTypeFace( ftFace ),
215   mPath( path ),
216   mRequestedPointSize( requestedPointSize ),
217   mFaceIndex( face ),
218   mMetrics( metrics ),
219   mCharacterSet( nullptr ),
220   mFixedSizeIndex( fixedSizeIndex ),
221   mFixedWidthPixels( fixedWidth ),
222   mFixedHeightPixels( fixedHeight ),
223   mVectorFontId( 0u ),
224   mFontId( 0u ),
225   mIsFixedSizeBitmap( true ),
226   mHasColorTables( hasColorTables )
227 {
228 }
229
230 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
231                             unsigned int verticalDpi )
232 : mFreeTypeLibrary( nullptr ),
233   mDpiHorizontal( horizontalDpi ),
234   mDpiVertical( verticalDpi ),
235   mDefaultFontDescription(),
236   mSystemFonts(),
237   mDefaultFonts(),
238   mFontIdCache(),
239   mFontFaceCache(),
240   mValidatedFontCache(),
241   mFontDescriptionCache( 1u ),
242   mCharacterSetCache(),
243   mFontDescriptionSizeCache(),
244   mVectorFontCache( nullptr ),
245   mEllipsisCache(),
246   mEmbeddedItemCache(),
247   mDefaultFontDescriptionCached( false )
248 {
249   mCharacterSetCache.Resize( 1u );
250
251   int error = FT_Init_FreeType( &mFreeTypeLibrary );
252   if( FT_Err_Ok != error )
253   {
254     DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Init error: %d\n", error );
255   }
256
257 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
258   mVectorFontCache = new VectorFontCache( mFreeTypeLibrary );
259 #endif
260 }
261
262 FontClient::Plugin::~Plugin()
263 {
264   ClearFallbackCache( mFallbackCache );
265
266   // Free the resources allocated by the FcCharSet objects.
267   DestroyCharacterSets( mDefaultFontCharacterSets );
268   DestroyCharacterSets( mCharacterSetCache );
269   ClearCharacterSetFromFontFaceCache();
270
271 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
272   delete mVectorFontCache;
273 #endif
274   FT_Done_FreeType( mFreeTypeLibrary );
275 }
276
277 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
278                                  unsigned int verticalDpi )
279 {
280   mDpiHorizontal = horizontalDpi;
281   mDpiVertical = verticalDpi;
282 }
283
284 void FontClient::Plugin::ResetSystemDefaults()
285 {
286   mDefaultFontDescriptionCached = false;
287 }
288
289 void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList )
290 {
291   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::SetFontList\n" );
292   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
293   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
294   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
295   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
296
297   fontList.clear();
298
299   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription ); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
300
301   FcResult result = FcResultMatch;
302
303   // Match the pattern.
304   FcFontSet* fontSet = FcFontSort( nullptr /* use default configure */,
305                                    fontFamilyPattern,
306                                    false /* don't trim */,
307                                    nullptr,
308                                    &result ); // FcFontSort creates a font set that needs to be destroyed by calling FcFontSetDestroy.
309
310   if( nullptr != fontSet )
311   {
312     DALI_LOG_INFO( gLogFilter, Debug::General, "  number of fonts found : [%d]\n", fontSet->nfont );
313     // Reserve some space to avoid reallocations.
314     fontList.reserve( fontSet->nfont );
315
316     for( int i = 0u; i < fontSet->nfont; ++i )
317     {
318       FcPattern* fontPattern = fontSet->fonts[i];
319
320       FontPath path;
321
322       // Skip fonts with no path
323       if( GetFcString( fontPattern, FC_FILE, path ) )
324       {
325         // Retrieve the character set. Need to call FcCharSetDestroy to free the resources.
326         FcCharSet* characterSet = nullptr;
327         FcPatternGetCharSet( fontPattern, FC_CHARSET, 0u, &characterSet );
328
329         // Increase the reference counter of the character set.
330         characterSetList.PushBack( FcCharSetCopy( characterSet ) );
331
332         fontList.push_back( FontDescription() );
333         FontDescription& newFontDescription = fontList.back();
334
335         newFontDescription.path = std::move( path );
336
337         int width = 0;
338         int weight = 0;
339         int slant = 0;
340         GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
341         GetFcInt( fontPattern, FC_WIDTH, width );
342         GetFcInt( fontPattern, FC_WEIGHT, weight );
343         GetFcInt( fontPattern, FC_SLANT, slant );
344         newFontDescription.width = IntToWidthType( width );
345         newFontDescription.weight = IntToWeightType( weight );
346         newFontDescription.slant = IntToSlantType( slant );
347
348         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  description; family : [%s]\n", newFontDescription.family.c_str() );
349         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", newFontDescription.path.c_str() );
350         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[newFontDescription.width] );
351         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[newFontDescription.weight] );
352         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[newFontDescription.slant] );
353       }
354     }
355
356     // Destroys the font set created by FcFontSort.
357     FcFontSetDestroy( fontSet );
358   }
359   else
360   {
361     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  No fonts found.\n" );
362   }
363
364   // Destroys the pattern created by FcPatternCreate in CreateFontFamilyPattern.
365   FcPatternDestroy( fontFamilyPattern );
366
367   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::SetFontList\n" );
368 }
369
370 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
371 {
372   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultFonts\n" );
373
374   if( mDefaultFonts.empty() )
375   {
376     FontDescription fontDescription;
377     fontDescription.family = DEFAULT_FONT_FAMILY_NAME;  // todo This could be set to the Platform font
378     fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
379     fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
380     fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
381     SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets );
382   }
383
384   defaultFonts = mDefaultFonts;
385
386   DALI_LOG_INFO( gLogFilter, Debug::General, "  number of default fonts : [%d]\n", mDefaultFonts.size() );
387   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultFonts\n" );
388 }
389
390 void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
391 {
392   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultPlatformFontDescription\n");
393
394   if( !mDefaultFontDescriptionCached )
395   {
396     // Clear any font config stored info in the caches.
397
398     // Decrease the reference counter and eventually free the resources allocated by FcCharSet objects.
399     DestroyCharacterSets( mDefaultFontCharacterSets );
400     DestroyCharacterSets( mCharacterSetCache );
401     mDefaultFontCharacterSets.Clear();
402     mCharacterSetCache.Clear();
403
404     for( auto& item : mFallbackCache )
405     {
406       // Decrease the reference counter and eventually free the resources allocated by FcCharSet objects.
407       DestroyCharacterSets( *item.characterSets );
408
409       delete item.characterSets;
410       item.characterSets = nullptr;
411     }
412
413     // Set the character set pointer as null. Will be created again the next time IsCharacterSupportedByFont()
414     ClearCharacterSetFromFontFaceCache();
415
416     // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
417     FcInitReinitialize();
418
419     FcPattern* matchPattern = FcPatternCreate(); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
420
421     if( nullptr != matchPattern )
422     {
423       FcConfigSubstitute( nullptr, matchPattern, FcMatchPattern );
424       FcDefaultSubstitute( matchPattern );
425
426       FcCharSet* characterSet = nullptr;
427       MatchFontDescriptionToPattern( matchPattern, mDefaultFontDescription, &characterSet );
428       // Decrease the reference counter of the character set as it's not stored.
429       FcCharSetDestroy( characterSet );
430
431       // Destroys the pattern created.
432       FcPatternDestroy( matchPattern );
433     }
434
435     // Create again the character sets as they are not valid after FcInitReinitialize()
436
437     for( const auto& description : mDefaultFonts )
438     {
439       mDefaultFontCharacterSets.PushBack( FcCharSetCopy( CreateCharacterSetFromDescription( description ) ) );
440     }
441
442     for( const auto& description : mFontDescriptionCache )
443     {
444       mCharacterSetCache.PushBack( FcCharSetCopy( CreateCharacterSetFromDescription( description ) ) );
445     }
446
447     for( auto& item : mFallbackCache )
448     {
449       if( nullptr != item.fallbackFonts )
450       {
451         if( nullptr == item.characterSets )
452         {
453           item.characterSets = new CharacterSetList;
454         }
455
456         for( const auto& description : *( item.fallbackFonts ) )
457         {
458           item.characterSets->PushBack( FcCharSetCopy( CreateCharacterSetFromDescription( description ) ) );
459         }
460       }
461     }
462
463     mDefaultFontDescriptionCached = true;
464   }
465
466   fontDescription.path   = mDefaultFontDescription.path;
467   fontDescription.family = mDefaultFontDescription.family;
468   fontDescription.width  = mDefaultFontDescription.width;
469   fontDescription.weight = mDefaultFontDescription.weight;
470   fontDescription.slant  = mDefaultFontDescription.slant;
471
472   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
473   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
474   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
475   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
476   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
477   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultPlatformFontDescription\n");
478 }
479
480 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
481 {
482   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetSystemFonts\n");
483
484   if( mSystemFonts.empty() )
485   {
486     InitSystemFonts();
487   }
488
489   systemFonts = mSystemFonts;
490   DALI_LOG_INFO( gLogFilter, Debug::General, "  number of system fonts : [%d]\n", mSystemFonts.size() );
491   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetSystemFonts\n");
492 }
493
494 void FontClient::Plugin::GetDescription( FontId id,
495                                          FontDescription& fontDescription ) const
496 {
497   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDescription\n");
498   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
499   const FontId index = id - 1u;
500
501   if( ( id > 0u ) && ( index < mFontIdCache.Count() ) )
502   {
503     const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
504     switch( fontIdCacheItem.type )
505     {
506       case FontDescription::FACE_FONT:
507       {
508         for( const auto& item : mFontDescriptionSizeCache )
509         {
510           if( item.fontId == fontIdCacheItem.id )
511           {
512             fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
513
514             DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
515             DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
516             DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
517             DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
518             DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
519             DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
520             return;
521           }
522         }
523         break;
524       }
525       case FontDescription::BITMAP_FONT:
526       {
527         fontDescription.type = FontDescription::BITMAP_FONT;
528         fontDescription.family = mBitmapFontCache[fontIdCacheItem.id].font.name;
529         break;
530       }
531       default:
532       {
533         DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
534         fontDescription.type = FontDescription::INVALID;
535         fontDescription.family.clear();
536       }
537     }
538   }
539
540   DALI_LOG_INFO( gLogFilter, Debug::General, "  No description found for the font ID %d\n", id );
541   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
542 }
543
544 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
545 {
546   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetPointSize\n");
547   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
548   const FontId index = id - 1u;
549
550   if( ( id > 0u ) &&
551       ( index < mFontIdCache.Count() ) )
552   {
553     const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
554
555     switch( fontIdCacheItem.type )
556     {
557       case FontDescription::FACE_FONT:
558       {
559         DALI_LOG_INFO( gLogFilter, Debug::General, "  point size : %d\n", ( *( mFontFaceCache.begin() + fontIdCacheItem.id ) ).mRequestedPointSize );
560         DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
561         return ( *( mFontFaceCache.begin() + fontIdCacheItem.id ) ).mRequestedPointSize;
562       }
563       case FontDescription::BITMAP_FONT:
564       {
565         return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
566       }
567       default:
568       {
569         DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
570       }
571     }
572   }
573   else
574   {
575     DALI_LOG_INFO( gLogFilter, Debug::General, "  Invalid font ID %d\n", id );
576   }
577
578   DALI_LOG_INFO( gLogFilter, Debug::General, "  default point size : %d\n", TextAbstraction::FontClient::DEFAULT_POINT_SIZE );
579   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
580   return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
581 }
582
583 bool FontClient::Plugin::IsCharacterSupportedByFont( FontId fontId, Character character )
584 {
585   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::IsCharacterSupportedByFont\n");
586   DALI_LOG_INFO( gLogFilter, Debug::General, "    font id : %d\n", fontId );
587   DALI_LOG_INFO( gLogFilter, Debug::General, "  character : %p\n", character );
588
589   if( ( fontId < 1u ) || ( fontId > mFontIdCache.Count() ) )
590   {
591     DALI_LOG_INFO( gLogFilter, Debug::General, "  Invalid font id. Number of items in the cache: %d\n",mFontIdCache.Count());
592     DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
593     return false;
594   }
595
596   --fontId;
597
598   bool isSupported = false;
599
600   const FontIdCacheItem& fontIdCacheItem = mFontIdCache[fontId];
601
602   switch( fontIdCacheItem.type )
603   {
604     case FontDescription::FACE_FONT:
605     {
606       if( fontIdCacheItem.id < mFontFaceCache.size() )
607       {
608         FontFaceCacheItem& cacheItem = mFontFaceCache[fontIdCacheItem.id];
609
610         if( nullptr == cacheItem.mCharacterSet )
611         {
612           // Create again the character set.
613           // It can be null if the ResetSystemDefaults() method has been called.
614
615           FontDescription description;
616           description.path = cacheItem.mPath;
617           description.family = std::move( FontFamily( cacheItem.mFreeTypeFace->family_name ) );
618           description.weight = FontWeight::NONE;
619           description.width = FontWidth::NONE;
620           description.slant = FontSlant::NONE;
621
622           // Note FreeType doesn't give too much info to build a proper font style.
623           if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC )
624           {
625             description.slant = FontSlant::ITALIC;
626           }
627           if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_BOLD )
628           {
629             description.weight = FontWeight::BOLD;
630           }
631
632           cacheItem.mCharacterSet = FcCharSetCopy( CreateCharacterSetFromDescription( description ) );
633         }
634
635         isSupported = FcCharSetHasChar( cacheItem.mCharacterSet, character );
636       }
637       break;
638     }
639     case FontDescription::BITMAP_FONT:
640     {
641       const BitmapFont& bitmapFont = mBitmapFontCache[fontIdCacheItem.id].font;
642
643       for( const auto& glyph : bitmapFont.glyphs )
644       {
645         if( glyph.utf32 == character )
646         {
647           isSupported = true;
648           break;
649         }
650       }
651       break;
652     }
653     default:
654     {
655       DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
656     }
657   }
658
659   DALI_LOG_INFO( gLogFilter, Debug::General, "  is supported : %s\n", (isSupported ? "true" : "false") );
660   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
661   return isSupported;
662 }
663
664 FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList,
665                                                  const CharacterSetList& characterSetList,
666                                                  Character character,
667                                                  PointSize26Dot6 requestedPointSize,
668                                                  bool preferColor )
669 {
670   DALI_ASSERT_DEBUG( ( fontList.size() == characterSetList.Count() ) && "FontClient::Plugin::FindFontForCharacter. Different number of fonts and character sets." );
671
672   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFontForCharacter\n" );
673   DALI_LOG_INFO( gLogFilter, Debug::General, "           character : %p\n", character );
674   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
675   DALI_LOG_INFO( gLogFilter, Debug::General, "         preferColor : %s\n", ( preferColor ? "true" : "false" ) );
676
677   FontId fontId = 0u;
678   bool foundColor = false;
679
680   DALI_LOG_INFO( gLogFilter, Debug::General, "  number of fonts : %d\n", fontList.size() );
681
682   // Traverse the list of fonts.
683   // Check for each font if supports the character.
684   for( unsigned int index = 0u, numberOfFonts = fontList.size(); index < numberOfFonts; ++index )
685   {
686     const FontDescription& description = fontList[index];
687     const FcCharSet* const characterSet = characterSetList[index];
688
689     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  description; family : [%s]\n", description.family.c_str() );
690     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", description.path.c_str() );
691     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[description.width] );
692     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[description.weight] );
693     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[description.slant] );
694
695     bool foundInRanges = false;
696     if( nullptr != characterSet )
697     {
698       foundInRanges = FcCharSetHasChar( characterSet, character );
699     }
700
701     if( foundInRanges )
702     {
703       fontId = GetFontId( description,
704                           requestedPointSize,
705                           0u );
706
707       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "     font id : %d\n", fontId );
708
709       if( preferColor )
710       {
711         if( ( fontId > 0 ) &&
712             ( fontId - 1u < mFontIdCache.Count() ) )
713         {
714           const FontFaceCacheItem& item = mFontFaceCache[mFontIdCache[fontId - 1u].id];
715
716           foundColor = item.mHasColorTables;
717         }
718
719         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  foundColor : %s\n", ( foundColor ? "true" : "false" ) );
720       }
721
722       // Keep going unless we prefer a different (color) font.
723       if( !preferColor || foundColor )
724       {
725         break;
726       }
727     }
728   }
729
730   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", fontId );
731   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFontForCharacter\n" );
732   return fontId;
733 }
734
735 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
736                                             PointSize26Dot6 requestedPointSize,
737                                             bool preferColor )
738 {
739   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindDefaultFont\n" );
740   DALI_LOG_INFO( gLogFilter, Debug::General, "           character : %p\n", charcode );
741   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
742   DALI_LOG_INFO( gLogFilter, Debug::General, "         preferColor : %s\n", ( preferColor ? "true" : "false" ) );
743
744   FontId fontId(0);
745
746   // Create the list of default fonts if it has not been created.
747   if( mDefaultFonts.empty() )
748   {
749     FontDescription fontDescription;
750     fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
751     fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
752     fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
753     fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
754
755     SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets );
756   }
757   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of default fonts : %d\n", mDefaultFonts.size() );
758
759
760   // Traverse the list of default fonts.
761   // Check for each default font if supports the character.
762   fontId = FindFontForCharacter( mDefaultFonts, mDefaultFontCharacterSets, charcode, requestedPointSize, preferColor );
763
764   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", fontId );
765   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindDefaultFont\n" );
766
767   return fontId;
768 }
769
770 FontId FontClient::Plugin::FindFallbackFont( Character charcode,
771                                              const FontDescription& preferredFontDescription,
772                                              PointSize26Dot6 requestedPointSize,
773                                              bool preferColor )
774 {
775   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFont\n" );
776   DALI_LOG_INFO( gLogFilter, Debug::General, "           character : %p\n", charcode );
777   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
778   DALI_LOG_INFO( gLogFilter, Debug::General, "         preferColor : %s\n", ( preferColor ? "true" : "false" ) );
779
780   // The font id to be returned.
781   FontId fontId = 0u;
782
783   FontDescription fontDescription;
784
785   // Fill the font description with the preferred font description and complete with the defaults.
786   fontDescription.family = preferredFontDescription.family.empty() ? DEFAULT_FONT_FAMILY_NAME : preferredFontDescription.family;
787   fontDescription.weight = ( ( FontWeight::NONE == preferredFontDescription.weight ) ? IntToWeightType( DEFAULT_FONT_WEIGHT ) : preferredFontDescription.weight );
788   fontDescription.width = ( ( FontWidth::NONE == preferredFontDescription.width ) ? IntToWidthType( DEFAULT_FONT_WIDTH ) : preferredFontDescription.width );
789   fontDescription.slant = ( ( FontSlant::NONE == preferredFontDescription.slant ) ? IntToSlantType( DEFAULT_FONT_SLANT ) : preferredFontDescription.slant );
790
791   DALI_LOG_INFO( gLogFilter, Debug::General, "  preferredFontDescription --> fontDescription\n" );
792   DALI_LOG_INFO( gLogFilter, Debug::General, "  [%s] --> [%s]\n", preferredFontDescription.family.c_str(), fontDescription.family.c_str() );
793   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  [%s] --> [%s]\n", FontWeight::Name[preferredFontDescription.weight], FontWeight::Name[fontDescription.weight] );
794   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  [%s] --> [%s]\n", FontWidth::Name[preferredFontDescription.width], FontWidth::Name[fontDescription.width] );
795   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  [%s] --> [%s]\n", FontSlant::Name[preferredFontDescription.slant], FontSlant::Name[fontDescription.slant] );
796
797   // Check first if the font's description has been queried before.
798   FontList* fontList = nullptr;
799   CharacterSetList* characterSetList = nullptr;
800
801   if( !FindFallbackFontList( fontDescription, fontList, characterSetList ) )
802   {
803     fontList = new FontList;
804     characterSetList = new CharacterSetList;
805
806     SetFontList( fontDescription, *fontList, *characterSetList );
807
808     // Add the font-list to the cache.
809     mFallbackCache.push_back( std::move( FallbackCacheItem( std::move( fontDescription ), fontList, characterSetList ) ) );
810   }
811
812   if( fontList && characterSetList )
813   {
814     fontId = FindFontForCharacter( *fontList, *characterSetList, charcode, requestedPointSize, preferColor );
815   }
816
817   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", fontId );
818   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFont\n");
819   return fontId;
820 }
821
822 FontId FontClient::Plugin::GetFontId( const FontPath& path,
823                                       PointSize26Dot6 requestedPointSize,
824                                       FaceIndex faceIndex,
825                                       bool cacheDescription )
826 {
827   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" );
828   DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
829   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
830
831   FontId id = 0u;
832
833   if( nullptr != mFreeTypeLibrary )
834   {
835     FontId foundId = 0u;
836     if( FindFont( path, requestedPointSize, faceIndex, foundId ) )
837     {
838       id = foundId;
839     }
840     else
841     {
842       id = CreateFont( path, requestedPointSize, faceIndex, cacheDescription );
843     }
844   }
845
846   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
847   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" );
848
849   return id;
850 }
851
852 FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
853                                       PointSize26Dot6 requestedPointSize,
854                                       FaceIndex faceIndex )
855 {
856   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" );
857   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
858   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
859   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
860   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
861   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
862   DALI_LOG_INFO( gLogFilter, Debug::General, "   requestedPointSize : %d\n", requestedPointSize );
863
864   // This method uses three vectors which caches:
865   // * The bitmap font cache
866   // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
867   // * The path to font file names.
868   // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
869
870   // 1) Checks if the font description matches with a previously loaded bitmap font.
871   //    Returns if a font is found.
872   // 2) Checks in the cache if the font's description has been validated before.
873   //    If it was it gets an index to the vector with paths to font file names. Otherwise,
874   //    retrieves using font config a path to a font file name which matches with the
875   //    font's description. The path is stored in the cache.
876   //
877   // 3) Checks in the cache if the pair 'font point size, index to the vector with paths to
878   //    font file names' exists. If exists, it gets the font id. If it doesn't it calls
879   //    the GetFontId() method with the path to the font file name and the point size to
880   //    get the font id.
881
882   // The font id to be returned.
883   FontId fontId = 0u;
884
885   // Check first if the font description matches with a previously loaded bitmap font.
886   if( FindBitmapFont( fontDescription.family, fontId ) )
887   {
888     return fontId;
889   }
890
891   // Check if the font's description have been validated before.
892   FontDescriptionId validatedFontId = 0u;
893
894   if( !FindValidatedFont( fontDescription,
895                           validatedFontId ) )
896   {
897     // Use font config to validate the font's description.
898     ValidateFont( fontDescription,
899                   validatedFontId );
900   }
901
902   FontId fontFaceId = 0u;
903   // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
904   if( !FindFont( validatedFontId, requestedPointSize, fontFaceId ) )
905   {
906     // Retrieve the font file name path.
907     const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
908
909     // Retrieve the font id. Do not cache the description as it has been already cached.
910     fontId = GetFontId( description.path,
911                         requestedPointSize,
912                         faceIndex,
913                         false );
914
915     fontFaceId = mFontIdCache[fontId-1u].id;
916     mFontFaceCache[fontFaceId].mCharacterSet = mCharacterSetCache[validatedFontId];
917
918     // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
919     mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId,
920                                                                        requestedPointSize,
921                                                                        fontFaceId ) );
922   }
923   else
924   {
925     fontId = mFontFaceCache[fontFaceId].mFontId + 1u;
926   }
927
928   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", fontId );
929   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" );
930
931   return fontId;
932 }
933
934 FontId FontClient::Plugin::GetFontId( const BitmapFont& bitmapFont )
935 {
936   for( const auto& item : mBitmapFontCache )
937   {
938     if( bitmapFont.name == item.font.name )
939     {
940       return item.id + 1u;
941     }
942   }
943
944   BitmapFontCacheItem bitmapFontCacheItem;
945   bitmapFontCacheItem.font = bitmapFont;
946   bitmapFontCacheItem.id = mFontIdCache.Count();
947
948   // Resize the vector with the pixel buffers.
949   bitmapFontCacheItem.pixelBuffers.resize( bitmapFont.glyphs.size() );
950
951   // Traverse all the glyphs and load the pixel buffer of those with ascender and descender equal to zero.
952   unsigned int index = 0u;
953   for( auto& glyph : bitmapFontCacheItem.font.glyphs )
954   {
955     Devel::PixelBuffer& pixelBuffer = bitmapFontCacheItem.pixelBuffers[index];
956
957     if( EqualsZero( glyph.ascender ) && EqualsZero( glyph.descender ) )
958     {
959       // Load the glyph.
960       pixelBuffer = LoadImageFromFile( glyph.url );
961
962       if( pixelBuffer )
963       {
964         glyph.ascender = static_cast<float>(pixelBuffer.GetHeight());
965       }
966     }
967
968     bitmapFontCacheItem.font.ascender = std::max( glyph.ascender, bitmapFontCacheItem.font.ascender );
969     bitmapFontCacheItem.font.descender = std::min( glyph.descender, bitmapFontCacheItem.font.descender );
970
971     ++index;
972   }
973
974   FontIdCacheItem fontIdCacheItem;
975   fontIdCacheItem.type = FontDescription::BITMAP_FONT;
976   fontIdCacheItem.id = mBitmapFontCache.size();
977
978   mBitmapFontCache.push_back( std::move( bitmapFontCacheItem ) );
979   mFontIdCache.PushBack( fontIdCacheItem );
980
981   return bitmapFontCacheItem.id + 1u;
982 }
983
984 void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
985                                        FontDescriptionId& validatedFontId )
986 {
987   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::ValidateFont\n" );
988   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
989   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
990   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
991   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
992   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
993
994   // Create a font pattern.
995   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
996
997   FontDescription description;
998
999   FcCharSet* characterSet = nullptr;
1000   bool matched = MatchFontDescriptionToPattern( fontFamilyPattern, description, &characterSet );
1001   FcPatternDestroy( fontFamilyPattern );
1002
1003   if( matched && ( nullptr != characterSet ) )
1004   {
1005     // Set the index to the vector of paths to font file names.
1006     validatedFontId = mFontDescriptionCache.size();
1007
1008     DALI_LOG_INFO( gLogFilter, Debug::General, "  matched description; family : [%s]\n", description.family.c_str() );
1009     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                         path : [%s]\n", description.path.c_str() );
1010     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                        width : [%s]\n", FontWidth::Name[description.width] );
1011     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                       weight : [%s]\n", FontWeight::Name[description.weight] );
1012     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                        slant : [%s]\n\n", FontSlant::Name[description.slant] );
1013     DALI_LOG_INFO( gLogFilter, Debug::General, "  validatedFontId : %d\n", validatedFontId );
1014
1015     // Add the path to the cache.
1016     description.type = FontDescription::FACE_FONT;
1017     mFontDescriptionCache.push_back( description );
1018
1019     // The reference counter of the character set has already been increased in MatchFontDescriptionToPattern.
1020     mCharacterSetCache.PushBack( characterSet );
1021
1022     // Cache the index and the matched font's description.
1023     FontDescriptionCacheItem item( description,
1024                                    validatedFontId );
1025
1026     mValidatedFontCache.push_back( std::move( item ) );
1027
1028     if( ( fontDescription.family != description.family ) ||
1029         ( fontDescription.width != description.width )   ||
1030         ( fontDescription.weight != description.weight ) ||
1031         ( fontDescription.slant != description.slant ) )
1032     {
1033       // Cache the given font's description if it's different than the matched.
1034       FontDescriptionCacheItem item( fontDescription,
1035                                      validatedFontId );
1036
1037       mValidatedFontCache.push_back( std::move( item ) );
1038     }
1039   }
1040   else
1041   {
1042     DALI_LOG_INFO( gLogFilter, Debug::General, "  font validation failed for font [%s]\n", fontDescription.family.c_str() );
1043   }
1044
1045   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::ValidateFont\n" );
1046 }
1047
1048 void FontClient::Plugin::GetFontMetrics( FontId fontId,
1049                                          FontMetrics& metrics )
1050 {
1051   const FontId index = fontId - 1u;
1052
1053   if( ( fontId > 0 ) &&
1054       ( index < mFontIdCache.Count() ) )
1055   {
1056     const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
1057
1058     switch( fontIdCacheItem.type )
1059     {
1060       case FontDescription::FACE_FONT:
1061       {
1062         const FontFaceCacheItem& font = mFontFaceCache[fontIdCacheItem.id];
1063
1064         metrics = font.mMetrics;
1065
1066         // Adjust the metrics if the fixed-size font should be down-scaled
1067         if( font.mIsFixedSizeBitmap )
1068         {
1069           const float desiredFixedSize =  static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
1070
1071           if( desiredFixedSize > 0.f )
1072           {
1073             const float scaleFactor = desiredFixedSize / font.mFixedHeightPixels;
1074
1075             metrics.ascender = metrics.ascender * scaleFactor;
1076             metrics.descender = metrics.descender * scaleFactor;
1077             metrics.height = metrics.height * scaleFactor;
1078             metrics.underlinePosition = metrics.underlinePosition * scaleFactor;
1079             metrics.underlineThickness = metrics.underlineThickness * scaleFactor;
1080           }
1081         }
1082         break;
1083       }
1084       case FontDescription::BITMAP_FONT:
1085       {
1086         const BitmapFontCacheItem& bitmapFontCacheItem = mBitmapFontCache[fontIdCacheItem.id];
1087
1088         metrics.ascender = bitmapFontCacheItem.font.ascender;
1089         metrics.descender = bitmapFontCacheItem.font.descender;
1090         metrics.height = metrics.ascender - metrics.descender;
1091         metrics.underlinePosition = bitmapFontCacheItem.font.underlinePosition;
1092         metrics.underlineThickness = bitmapFontCacheItem.font.underlineThickness;
1093         break;
1094       }
1095       default:
1096       {
1097         DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
1098       }
1099     }
1100   }
1101   else
1102   {
1103     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId );
1104   }
1105 }
1106
1107 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
1108                                               Character charcode )
1109 {
1110   GlyphIndex glyphIndex = 0u;
1111   const FontId index = fontId - 1u;
1112
1113   if( ( fontId > 0u ) &&
1114       ( index < mFontIdCache.Count() ) )
1115   {
1116     const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
1117
1118     if( FontDescription::FACE_FONT == fontIdCacheItem.type )
1119     {
1120       FT_Face ftFace = mFontFaceCache[fontIdCacheItem.id].mFreeTypeFace;
1121
1122       glyphIndex = FT_Get_Char_Index( ftFace, charcode );
1123     }
1124   }
1125
1126   return glyphIndex;
1127 }
1128
1129 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
1130                                           uint32_t size,
1131                                           GlyphType type,
1132                                           bool horizontal )
1133 {
1134   if( VECTOR_GLYPH == type )
1135   {
1136     return GetVectorMetrics( array, size, horizontal );
1137   }
1138
1139   return GetBitmapMetrics( array, size, horizontal );
1140 }
1141
1142 bool FontClient::Plugin::GetBitmapMetrics( GlyphInfo* array,
1143                                            uint32_t size,
1144                                            bool horizontal )
1145 {
1146   bool success( true );
1147
1148   for( unsigned int i=0; i<size; ++i )
1149   {
1150     GlyphInfo& glyph = array[i];
1151
1152     FontId index = glyph.fontId - 1u;
1153
1154     if( ( glyph.fontId > 0u ) &&
1155         ( index < mFontIdCache.Count() ) )
1156     {
1157       const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
1158
1159       switch( fontIdCacheItem.type )
1160       {
1161       case FontDescription::FACE_FONT:
1162       {
1163         const FontFaceCacheItem& font = mFontFaceCache[fontIdCacheItem.id];
1164
1165         FT_Face ftFace = font.mFreeTypeFace;
1166
1167 #ifdef FREETYPE_BITMAP_SUPPORT
1168         // Check to see if we should be loading a Fixed Size bitmap?
1169         if( font.mIsFixedSizeBitmap )
1170         {
1171           FT_Select_Size( ftFace, font.mFixedSizeIndex ); ///< @todo: needs to be investigated why it's needed to select the size again.
1172           int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_COLOR );
1173           if ( FT_Err_Ok == error )
1174           {
1175             glyph.width = font.mFixedWidthPixels;
1176             glyph.height = font.mFixedHeightPixels;
1177             glyph.advance = font.mFixedWidthPixels;
1178             glyph.xBearing = 0.0f;
1179             glyph.yBearing = font.mFixedHeightPixels;
1180
1181             // Adjust the metrics if the fixed-size font should be down-scaled
1182             const float desiredFixedSize =  static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
1183
1184             if( desiredFixedSize > 0.f )
1185             {
1186               const float scaleFactor = desiredFixedSize / font.mFixedHeightPixels;
1187
1188               glyph.width = glyph.width * scaleFactor ;
1189               glyph.height = glyph.height * scaleFactor;
1190               glyph.advance = glyph.advance * scaleFactor;
1191               glyph.xBearing = glyph.xBearing * scaleFactor;
1192               glyph.yBearing = glyph.yBearing * scaleFactor;
1193
1194               glyph.scaleFactor = scaleFactor;
1195             }
1196           }
1197           else
1198           {
1199             DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetBitmapMetrics. FreeType Bitmap Load_Glyph error %d\n", error );
1200             success = false;
1201           }
1202         }
1203         else
1204 #endif
1205         {
1206           int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_NO_AUTOHINT );
1207
1208           if( FT_Err_Ok == error )
1209           {
1210             glyph.width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
1211             glyph.height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
1212             if( horizontal )
1213             {
1214               glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
1215               glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
1216             }
1217             else
1218             {
1219               glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
1220               glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
1221             }
1222           }
1223           else
1224           {
1225             success = false;
1226           }
1227         }
1228         break;
1229       }
1230       case FontDescription::BITMAP_FONT:
1231       {
1232         BitmapFontCacheItem& bitmapFontCacheItem = mBitmapFontCache[fontIdCacheItem.id];
1233
1234         unsigned int index = 0u;
1235         for( auto& item : bitmapFontCacheItem.font.glyphs )
1236         {
1237           if( item.utf32 == glyph.index )
1238           {
1239             Devel::PixelBuffer& pixelBuffer = bitmapFontCacheItem.pixelBuffers[index];
1240             if( !pixelBuffer )
1241             {
1242               pixelBuffer = LoadImageFromFile( item.url );
1243             }
1244
1245             glyph.width  = static_cast< float >( pixelBuffer.GetWidth() );
1246             glyph.height = static_cast< float >( pixelBuffer.GetHeight() );
1247             glyph.xBearing = 0.f;
1248             glyph.yBearing = glyph.height + item.descender;
1249             glyph.advance = glyph.width;
1250             glyph.scaleFactor = 1.f;
1251             break;
1252           }
1253           ++index;
1254         }
1255
1256         success = true;
1257         break;
1258       }
1259       default:
1260       {
1261         DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
1262       }
1263       }
1264     }
1265     else
1266     {
1267       // Check if it's an embedded image.
1268       if( ( 0u == glyph.fontId ) && ( 0u != glyph.index ) && ( glyph.index <= mEmbeddedItemCache.Count() ) )
1269       {
1270         const EmbeddedItem& item = mEmbeddedItemCache[glyph.index - 1u];
1271
1272         glyph.width = static_cast<float>( item.width );
1273         glyph.height = static_cast<float>( item.height );
1274         glyph.xBearing = 0.f;
1275         glyph.yBearing = glyph.height;
1276         glyph.advance = glyph.width;
1277         glyph.scaleFactor = 1.f;
1278       }
1279       else
1280       {
1281         success = false;
1282       }
1283     }
1284   }
1285
1286   return success;
1287 }
1288
1289 bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array,
1290                                            uint32_t size,
1291                                            bool horizontal )
1292 {
1293 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
1294   bool success( true );
1295
1296   for( unsigned int i = 0u; i < size; ++i )
1297   {
1298     FontId fontId = array[i].fontId;
1299
1300     if( ( fontId > 0u ) &&
1301         ( fontId - 1u ) < mFontIdCache.Count() )
1302     {
1303       FontFaceCacheItem& font = mFontFaceCache[mFontIdCache[fontId - 1u].id];
1304
1305       if( ! font.mVectorFontId )
1306       {
1307         font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
1308       }
1309
1310       mVectorFontCache->GetGlyphMetrics( font.mVectorFontId, array[i] );
1311
1312       // Vector metrics are in EMs, convert to pixels
1313       const float scale = ( static_cast<float>( font.mRequestedPointSize ) * FROM_266 ) * static_cast<float>( mDpiVertical ) / POINTS_PER_INCH;
1314       array[i].width    *= scale;
1315       array[i].height   *= scale;
1316       array[i].xBearing *= scale;
1317       array[i].yBearing *= scale;
1318       array[i].advance  *= scale;
1319     }
1320     else
1321     {
1322       success = false;
1323     }
1324   }
1325
1326   return success;
1327 #else
1328   return false;
1329 #endif
1330 }
1331
1332 void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
1333 {
1334   const FontId index = fontId - 1u;
1335
1336   if( ( fontId > 0u ) &&
1337       ( index < mFontIdCache.Count() ) )
1338   {
1339     const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
1340
1341     switch( fontIdCacheItem.type )
1342     {
1343     case FontDescription::FACE_FONT:
1344     {
1345       // For the software italics.
1346       bool isShearRequired = false;
1347
1348       const FontFaceCacheItem& fontFaceCacheItem = mFontFaceCache[fontIdCacheItem.id];
1349       FT_Face ftFace = fontFaceCacheItem.mFreeTypeFace;
1350
1351       FT_Error error;
1352
1353 #ifdef FREETYPE_BITMAP_SUPPORT
1354       // Check to see if this is fixed size bitmap
1355       if( fontFaceCacheItem.mIsFixedSizeBitmap )
1356       {
1357         error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1358       }
1359       else
1360 #endif
1361       {
1362         error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_NO_AUTOHINT );
1363       }
1364       if( FT_Err_Ok == error )
1365       {
1366         if( isBoldRequired && !( ftFace->style_flags & FT_STYLE_FLAG_BOLD ) )
1367         {
1368           // Does the software bold.
1369           FT_GlyphSlot_Embolden( ftFace->glyph );
1370         }
1371
1372         if( isItalicRequired && !( ftFace->style_flags & FT_STYLE_FLAG_ITALIC ) )
1373         {
1374           // Will do the software italic.
1375           isShearRequired = true;
1376         }
1377
1378         FT_Glyph glyph;
1379         error = FT_Get_Glyph( ftFace->glyph, &glyph );
1380
1381         // Convert to bitmap if necessary
1382         if ( FT_Err_Ok == error )
1383         {
1384           if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
1385           {
1386             // Check whether we should create a bitmap for the outline
1387             if( glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0 )
1388             {
1389               // Set up a stroker
1390               FT_Stroker stroker;
1391               error = FT_Stroker_New( mFreeTypeLibrary, &stroker );
1392
1393               if( FT_Err_Ok == error )
1394               {
1395                 FT_Stroker_Set( stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0 );
1396                 error = FT_Glyph_StrokeBorder( &glyph, stroker, 0, 1 );
1397
1398                 if( FT_Err_Ok == error )
1399                 {
1400                   FT_Stroker_Done( stroker );
1401                 }
1402                 else
1403                 {
1404                   DALI_LOG_ERROR( "FT_Glyph_StrokeBorder Failed with error: %d\n", error );
1405                 }
1406               }
1407               else
1408               {
1409                 DALI_LOG_ERROR( "FT_Stroker_New Failed with error: %d\n", error );
1410               }
1411             }
1412
1413             error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
1414             if( FT_Err_Ok == error )
1415             {
1416               FT_BitmapGlyph bitmapGlyph = reinterpret_cast< FT_BitmapGlyph >( glyph );
1417               ConvertBitmap( data, bitmapGlyph->bitmap, isShearRequired );
1418             }
1419             else
1420             {
1421               DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Get_Glyph Failed with error: %d\n", error );
1422             }
1423           }
1424           else
1425           {
1426             ConvertBitmap( data, ftFace->glyph->bitmap, isShearRequired );
1427           }
1428
1429           // Created FT_Glyph object must be released with FT_Done_Glyph
1430           FT_Done_Glyph( glyph );
1431         }
1432       }
1433       else
1434       {
1435         DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Load_Glyph Failed with error: %d\n", error );
1436       }
1437       break;
1438     }
1439     case FontDescription::BITMAP_FONT:
1440     {
1441       BitmapFontCacheItem& bitmapFontCacheItem = mBitmapFontCache[fontIdCacheItem.id];
1442
1443       unsigned int index = 0u;
1444       for( auto& item : bitmapFontCacheItem.font.glyphs )
1445       {
1446         if( item.utf32 == glyphIndex )
1447         {
1448           Devel::PixelBuffer& pixelBuffer = bitmapFontCacheItem.pixelBuffers[index];
1449           if( !pixelBuffer )
1450           {
1451             pixelBuffer = LoadImageFromFile( item.url );
1452           }
1453
1454           data.width = pixelBuffer.GetWidth();
1455           data.height = pixelBuffer.GetHeight();
1456
1457           ConvertBitmap( data, data.width, data.height, pixelBuffer.GetBuffer() );
1458
1459           // Sets the pixel format.
1460           data.format = pixelBuffer.GetPixelFormat();
1461           break;
1462         }
1463         ++index;
1464       }
1465       break;
1466     }
1467     default:
1468     {
1469       DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
1470     }
1471     }
1472   }
1473   else
1474   {
1475     if( ( 0u != glyphIndex ) && ( glyphIndex <= mEmbeddedItemCache.Count() ) )
1476     {
1477       // It's an embedded item.
1478       const EmbeddedItem& item = mEmbeddedItemCache[glyphIndex - 1u];
1479
1480       data.width = item.width;
1481       data.height = item.height;
1482       if( 0u != item.pixelBufferId )
1483       {
1484         Devel::PixelBuffer pixelBuffer = mPixelBufferCache[item.pixelBufferId-1u].pixelBuffer;
1485         if( pixelBuffer )
1486         {
1487           ConvertBitmap( data, pixelBuffer.GetWidth(), pixelBuffer.GetHeight(), pixelBuffer.GetBuffer() );
1488
1489           // Sets the pixel format.
1490           data.format = pixelBuffer.GetPixelFormat();
1491         }
1492       }
1493       else
1494       {
1495         // Creates the output buffer
1496         const unsigned int bufferSize = data.width * data.height * 4u;
1497         data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1498
1499         memset( data.buffer, 0u, bufferSize );
1500
1501         // Just creates a void buffer. Doesn't matter what pixel format is set as is the application code the responsible of filling it.
1502       }
1503     }
1504   }
1505 }
1506
1507 PixelData FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
1508 {
1509   TextAbstraction::FontClient::GlyphBufferData data;
1510
1511   CreateBitmap( fontId, glyphIndex, false, false, data, outlineWidth );
1512
1513   return PixelData::New( data.buffer,
1514                          data.width * data.height * Pixel::GetBytesPerPixel( data.format ),
1515                          data.width,
1516                          data.height,
1517                          data.format,
1518                          PixelData::DELETE_ARRAY );
1519 }
1520
1521 void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
1522 {
1523   blob = nullptr;
1524   blobLength = 0;
1525
1526 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
1527   if( ( fontId > 0u ) &&
1528       ( fontId - 1u < mFontIdCache.Count() ) )
1529   {
1530     const FontId fontFaceId = mFontIdCache[fontId - 1u].id;
1531     FontFaceCacheItem& font = mFontFaceCache[fontFaceId];
1532
1533     if( ! font.mVectorFontId )
1534     {
1535       font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
1536     }
1537
1538     mVectorFontCache->GetVectorBlob( font.mVectorFontId, fontFaceId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
1539   }
1540 #endif
1541 }
1542
1543 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize )
1544 {
1545   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetEllipsisGlyph\n" );
1546   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize %d.\n", requestedPointSize );
1547
1548   // First look into the cache if there is an ellipsis glyph for the requested point size.
1549   for( const auto& item : mEllipsisCache )
1550   {
1551     if( item.requestedPointSize != requestedPointSize )
1552     {
1553       // Use the glyph in the cache.
1554
1555       DALI_LOG_INFO( gLogFilter, Debug::General, "  glyph id %d found in the cache.\n", item.glyph.index );
1556       DALI_LOG_INFO( gLogFilter, Debug::General, "      font %d.\n", item.glyph.fontId );
1557       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
1558
1559       return item.glyph;
1560     }
1561   }
1562
1563   // No glyph has been found. Create one.
1564   mEllipsisCache.PushBack( EllipsisItem() );
1565   EllipsisItem& item = *( mEllipsisCache.End() - 1u );
1566
1567   item.requestedPointSize = requestedPointSize;
1568
1569   // Find a font for the ellipsis glyph.
1570   item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
1571                                        requestedPointSize,
1572                                        false );
1573
1574   // Set the character index to access the glyph inside the font.
1575   item.glyph.index = FT_Get_Char_Index( mFontFaceCache[mFontIdCache[item.glyph.fontId-1u].id].mFreeTypeFace,
1576                                         ELLIPSIS_CHARACTER );
1577
1578   GetBitmapMetrics( &item.glyph, 1u, true );
1579
1580   DALI_LOG_INFO( gLogFilter, Debug::General, "  glyph id %d found in the cache.\n", item.glyph.index );
1581   DALI_LOG_INFO( gLogFilter, Debug::General, "      font %d.\n", item.glyph.fontId );
1582   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
1583
1584   return item.glyph;
1585 }
1586
1587 bool FontClient::Plugin::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
1588 {
1589   FT_Error error = -1;
1590
1591   const FontId index = fontId - 1u;
1592
1593 #ifdef FREETYPE_BITMAP_SUPPORT
1594   if( ( fontId > 0u ) &&
1595       ( index < mFontIdCache.Count() ) )
1596   {
1597     const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
1598
1599     switch( fontIdCacheItem.type )
1600     {
1601     case FontDescription::FACE_FONT:
1602     {
1603       const FontFaceCacheItem& item = mFontFaceCache[fontIdCacheItem.id];
1604       FT_Face ftFace = item.mFreeTypeFace;
1605
1606       // Check to see if this is fixed size bitmap
1607       if( item.mHasColorTables )
1608       {
1609         error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1610       }
1611       break;
1612     }
1613     case FontDescription::BITMAP_FONT:
1614     {
1615       error = FT_Err_Ok; // Will return true;
1616       break;
1617     }
1618     default:
1619     {
1620       DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
1621     }
1622     }
1623   }
1624 #endif
1625
1626   return FT_Err_Ok == error;
1627 }
1628
1629 FT_FaceRec_* FontClient::Plugin::GetFreetypeFace( FontId fontId )
1630 {
1631   FT_Face fontFace = nullptr;
1632
1633   const FontId index = fontId - 1u;
1634   if( ( fontId > 0u ) &&
1635       ( index < mFontIdCache.Count() ) )
1636   {
1637     const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
1638
1639     if( FontDescription::FACE_FONT == fontIdCacheItem.type )
1640     {
1641       fontFace = mFontFaceCache[fontIdCacheItem.id].mFreeTypeFace;
1642     }
1643   }
1644   return fontFace;
1645 }
1646
1647 FontDescription::Type FontClient::Plugin::GetFontType( FontId fontId )
1648 {
1649   const FontId index = fontId - 1u;
1650   if( ( fontId > 0u ) &&
1651       ( index < mFontIdCache.Count() ) )
1652   {
1653     return mFontIdCache[index].type;
1654   }
1655   return FontDescription::INVALID;
1656 }
1657
1658 bool FontClient::Plugin::AddCustomFontDirectory( const FontPath& path )
1659 {
1660   // NULL as first parameter means the current configuration is used.
1661   return FcConfigAppFontAddDir( NULL, reinterpret_cast<const FcChar8 *>( path.c_str() ) );
1662 }
1663
1664 GlyphIndex FontClient::Plugin::CreateEmbeddedItem( const TextAbstraction::FontClient::EmbeddedItemDescription& description, Pixel::Format& pixelFormat )
1665 {
1666   EmbeddedItem embeddedItem;
1667
1668   embeddedItem.pixelBufferId = 0u;
1669   embeddedItem.width = description.width;
1670   embeddedItem.height = description.height;
1671
1672   pixelFormat = Pixel::A8;
1673
1674   if( !description.url.empty() )
1675   {
1676     // Check if the url is in the cache.
1677     PixelBufferId index = 0u;
1678
1679     for( const auto& cacheItem : mPixelBufferCache )
1680     {
1681       ++index;
1682       if( cacheItem.url == description.url )
1683       {
1684         // The url is in the pixel buffer cache.
1685         // Set the index +1 to the vector.
1686         embeddedItem.pixelBufferId = index;
1687         break;
1688       }
1689     }
1690
1691     Devel::PixelBuffer pixelBuffer;
1692     if( 0u == embeddedItem.pixelBufferId )
1693     {
1694       // The pixel buffer is not in the cache. Create one and cache it.
1695
1696       // Load the image from the url.
1697       pixelBuffer = LoadImageFromFile( description.url );
1698
1699       // Create the cache item.
1700       PixelBufferCacheItem pixelBufferCacheItem;
1701       pixelBufferCacheItem.pixelBuffer = pixelBuffer;
1702       pixelBufferCacheItem.url = description.url;
1703
1704       // Store the cache item in the cache.
1705       mPixelBufferCache.push_back( std::move( pixelBufferCacheItem ) );
1706
1707       // Set the pixel buffer id to the embedded item.
1708       embeddedItem.pixelBufferId = mPixelBufferCache.size();
1709     }
1710     else
1711     {
1712       // Retrieve the pixel buffer from the cache to set the pixel format.
1713       pixelBuffer = mPixelBufferCache[embeddedItem.pixelBufferId-1u].pixelBuffer;
1714     }
1715
1716     if( pixelBuffer )
1717     {
1718       // Set the size of the embedded item if it has not been set.
1719       if( 0u == embeddedItem.width )
1720       {
1721         embeddedItem.width = static_cast<unsigned int>( pixelBuffer.GetWidth() );
1722       }
1723
1724       if( 0u == embeddedItem.height )
1725       {
1726         embeddedItem.height = static_cast<unsigned int>( pixelBuffer.GetHeight() );
1727       }
1728
1729       // Set the pixel format.
1730       pixelFormat = pixelBuffer.GetPixelFormat();
1731     }
1732   }
1733
1734   // Find if the same embeddedItem has already been created.
1735   unsigned int index = 0u;
1736   for( const auto& item : mEmbeddedItemCache )
1737   {
1738     ++index;
1739     if( ( item.pixelBufferId == embeddedItem.pixelBufferId ) &&
1740         ( item.width == embeddedItem.width ) &&
1741         ( item.height == embeddedItem.height ) )
1742     {
1743       return index;
1744     }
1745   }
1746
1747   // Cache the embedded item.
1748   mEmbeddedItemCache.PushBack( embeddedItem );
1749
1750   return mEmbeddedItemCache.Count();
1751 }
1752
1753 void FontClient::Plugin::InitSystemFonts()
1754 {
1755   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::InitSystemFonts\n" );
1756
1757   FcFontSet* fontSet = GetFcFontSet(); // Creates a FcFontSet that needs to be destroyed by calling FcFontSetDestroy.
1758
1759   if( fontSet )
1760   {
1761     DALI_LOG_INFO( gLogFilter, Debug::General, "  number of system fonts : %d\n", fontSet->nfont );
1762
1763     // Reserve some space to avoid reallocations.
1764     mSystemFonts.reserve( fontSet->nfont );
1765
1766     for( int i = 0u; i < fontSet->nfont; ++i )
1767     {
1768       FcPattern* fontPattern = fontSet->fonts[i];
1769
1770       FontPath path;
1771
1772       // Skip fonts with no path
1773       if( GetFcString( fontPattern, FC_FILE, path ) )
1774       {
1775         mSystemFonts.push_back( FontDescription() );
1776         FontDescription& fontDescription = mSystemFonts.back();
1777
1778         fontDescription.path = std::move( path );
1779
1780         int width = 0;
1781         int weight = 0;
1782         int slant = 0;
1783         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
1784         GetFcInt( fontPattern, FC_WIDTH, width );
1785         GetFcInt( fontPattern, FC_WEIGHT, weight );
1786         GetFcInt( fontPattern, FC_SLANT, slant );
1787         fontDescription.width = IntToWidthType( width );
1788         fontDescription.weight = IntToWeightType( weight );
1789         fontDescription.slant = IntToSlantType( slant );
1790
1791         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  description; family : [%s]\n", fontDescription.family.c_str() );
1792         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1793         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1794         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1795         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1796       }
1797     }
1798
1799     // Destroys the font set created.
1800     FcFontSetDestroy( fontSet );
1801   }
1802   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::InitSystemFonts\n" );
1803 }
1804
1805 bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet )
1806 {
1807   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1808
1809   FcResult result = FcResultMatch;
1810   FcPattern* match = FcFontMatch( nullptr /* use default configure */, pattern, &result ); // Creates a new font pattern that needs to be destroyed by calling FcPatternDestroy.
1811
1812   const bool matched = nullptr != match;
1813   DALI_LOG_INFO( gLogFilter, Debug::General, "  pattern matched : %s\n", ( matched ? "true" : "false" ) );
1814
1815   if( matched )
1816   {
1817     int width = 0;
1818     int weight = 0;
1819     int slant = 0;
1820     GetFcString( match, FC_FILE, fontDescription.path );
1821     GetFcString( match, FC_FAMILY, fontDescription.family );
1822     GetFcInt( match, FC_WIDTH, width );
1823     GetFcInt( match, FC_WEIGHT, weight );
1824     GetFcInt( match, FC_SLANT, slant );
1825     fontDescription.width = IntToWidthType( width );
1826     fontDescription.weight = IntToWeightType( weight );
1827     fontDescription.slant = IntToSlantType( slant );
1828
1829     // Retrieve the character set and increase the reference counter.
1830     FcPatternGetCharSet( match, FC_CHARSET, 0u, characterSet );
1831     *characterSet = FcCharSetCopy( *characterSet );
1832
1833     // destroyed the matched pattern
1834     FcPatternDestroy( match );
1835
1836     DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1837     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1838     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1839     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1840     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1841   }
1842
1843   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1844   return matched;
1845 }
1846
1847 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription ) const
1848 {
1849   // create the cached font family lookup pattern
1850   // a pattern holds a set of names, each name refers to a property of the font
1851   FcPattern* fontFamilyPattern = FcPatternCreate(); // FcPatternCreate creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
1852
1853   if( !fontFamilyPattern )
1854   {
1855     return nullptr;
1856   }
1857
1858   // add a property to the pattern for the font family
1859   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
1860
1861   // add a property to the pattern for local setting.
1862   const char* locale = setlocale( LC_MESSAGES, NULL );
1863   if( locale != NULL)
1864   {
1865     FcPatternAddString( fontFamilyPattern, FC_LANG, reinterpret_cast<const FcChar8*>( locale ) );
1866   }
1867
1868   int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
1869   if( width < 0 )
1870   {
1871     // Use default.
1872     width = DEFAULT_FONT_WIDTH;
1873   }
1874
1875   int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
1876   if( weight < 0 )
1877   {
1878     // Use default.
1879     weight = DEFAULT_FONT_WEIGHT;
1880   }
1881
1882   int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
1883   if( slant < 0 )
1884   {
1885     // Use default.
1886     slant = DEFAULT_FONT_SLANT;
1887   }
1888
1889   FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
1890   FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
1891   FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
1892
1893   // modify the config, with the mFontFamilyPatterm
1894   FcConfigSubstitute( nullptr /* use default configure */, fontFamilyPattern, FcMatchPattern );
1895
1896   // provide default values for unspecified properties in the font pattern
1897   // e.g. patterns without a specified style or weight are set to Medium
1898   FcDefaultSubstitute( fontFamilyPattern );
1899
1900   return fontFamilyPattern;
1901 }
1902
1903 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
1904 {
1905   FcFontSet* fontset = nullptr;
1906
1907   // create a new pattern.
1908   // a pattern holds a set of names, each name refers to a property of the font
1909   FcPattern* pattern = FcPatternCreate();
1910
1911   if( nullptr != pattern )
1912   {
1913     // create an object set used to define which properties are to be returned in the patterns from FcFontList.
1914     FcObjectSet* objectSet = FcObjectSetCreate();
1915
1916     if( nullptr != objectSet )
1917     {
1918       // build an object set from a list of property names
1919       FcObjectSetAdd( objectSet, FC_FILE );
1920       FcObjectSetAdd( objectSet, FC_FAMILY );
1921       FcObjectSetAdd( objectSet, FC_WIDTH );
1922       FcObjectSetAdd( objectSet, FC_WEIGHT );
1923       FcObjectSetAdd( objectSet, FC_SLANT );
1924
1925       // get a list of fonts
1926       // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
1927       fontset = FcFontList( nullptr /* the default configuration is checked to be up to date, and used */, pattern, objectSet ); // Creates a FcFontSet that needs to be destroyed by calling FcFontSetDestroy.
1928
1929       // clear up the object set
1930       FcObjectSetDestroy( objectSet );
1931     }
1932
1933     // clear up the pattern
1934     FcPatternDestroy( pattern );
1935   }
1936
1937   return fontset;
1938 }
1939
1940 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1941                                       const char* const n,
1942                                       std::string& string )
1943 {
1944   FcChar8* file = nullptr;
1945   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1946
1947   if( FcResultMatch == retVal )
1948   {
1949     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1950     string.assign( reinterpret_cast<const char*>( file ) );
1951
1952     return true;
1953   }
1954
1955   return false;
1956 }
1957
1958 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
1959 {
1960   const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
1961
1962   if( FcResultMatch == retVal )
1963   {
1964     return true;
1965   }
1966
1967   return false;
1968 }
1969
1970 FontId FontClient::Plugin::CreateFont( const FontPath& path,
1971                                        PointSize26Dot6 requestedPointSize,
1972                                        FaceIndex faceIndex,
1973                                        bool cacheDescription )
1974 {
1975   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::CreateFont\n" );
1976   DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
1977   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1978
1979   FontId id = 0u;
1980
1981   // Create & cache new font face
1982   FT_Face ftFace;
1983   int error = FT_New_Face( mFreeTypeLibrary,
1984                            path.c_str(),
1985                            0,
1986                            &ftFace );
1987
1988   if( FT_Err_Ok == error )
1989   {
1990     // Check if a font is scalable.
1991     const bool isScalable = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_SCALABLE ) );
1992     const bool hasFixedSizedBitmaps = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_FIXED_SIZES ) ) && ( 0 != ftFace->num_fixed_sizes );
1993     const bool hasColorTables = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_COLOR ) );
1994     FontId fontFaceId = 0u;
1995
1996     DALI_LOG_INFO( gLogFilter, Debug::General, "            isScalable : [%s]\n", ( isScalable ? "true" : "false" ) );
1997     DALI_LOG_INFO( gLogFilter, Debug::General, "  hasFixedSizedBitmaps : [%s]\n", ( hasFixedSizedBitmaps ? "true" : "false" ) );
1998     DALI_LOG_INFO( gLogFilter, Debug::General, "        hasColorTables : [%s]\n", ( hasColorTables ? "true" : "false" ) );
1999
2000     // Check to see if the font contains fixed sizes?
2001     if( !isScalable && hasFixedSizedBitmaps )
2002     {
2003       PointSize26Dot6 actualPointSize = 0u;
2004       int fixedSizeIndex = 0;
2005       for( ; fixedSizeIndex < ftFace->num_fixed_sizes; ++fixedSizeIndex )
2006       {
2007         const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size;
2008         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  size index : %d, size : %d\n", fixedSizeIndex, fixedSize );
2009
2010         if( fixedSize >= requestedPointSize )
2011         {
2012           actualPointSize = fixedSize;
2013           break;
2014         }
2015       }
2016
2017       if( 0u == actualPointSize )
2018       {
2019         // The requested point size is bigger than the bigest fixed size.
2020         fixedSizeIndex = ftFace->num_fixed_sizes - 1;
2021         actualPointSize = ftFace->available_sizes[fixedSizeIndex].size;
2022       }
2023
2024       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize );
2025
2026       // Tell Freetype to use this size
2027       error = FT_Select_Size( ftFace, fixedSizeIndex );
2028       if ( FT_Err_Ok != error )
2029       {
2030         DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Select_Size error: %d\n", error );
2031       }
2032       else
2033       {
2034         const float fixedWidth  = static_cast<float>( ftFace->available_sizes[ fixedSizeIndex ].width );
2035         const float fixedHeight = static_cast<float>( ftFace->available_sizes[ fixedSizeIndex ].height );
2036
2037         // Indicate that the font is a fixed sized bitmap
2038         FontMetrics metrics( fixedHeight, // The ascender in pixels.
2039                              0.0f,
2040                              fixedHeight, // The height in pixels.
2041                              0.0f,
2042                              0.0f );
2043
2044         // Create the FreeType font face item to cache.
2045         FontFaceCacheItem fontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedSizeIndex, fixedWidth, fixedHeight, hasColorTables );
2046
2047         // Set the index to the font's id cache.
2048         fontFaceCacheItem.mFontId = mFontIdCache.Count();
2049
2050         // Create the font id item to cache.
2051         FontIdCacheItem fontIdCacheItem;
2052         fontIdCacheItem.type = FontDescription::FACE_FONT;
2053
2054         // Set the index to the FreeType font face cache.
2055         fontIdCacheItem.id = mFontFaceCache.size();
2056         fontFaceId = fontIdCacheItem.id + 1u;
2057
2058         // Cache the items.
2059         mFontFaceCache.push_back( fontFaceCacheItem );
2060         mFontIdCache.PushBack( fontIdCacheItem );
2061
2062         // Set the font id to be returned.
2063         id = mFontIdCache.Count();
2064       }
2065     }
2066     else
2067     {
2068       error = FT_Set_Char_Size( ftFace,
2069                                 0,
2070                                 requestedPointSize,
2071                                 mDpiHorizontal,
2072                                 mDpiVertical );
2073
2074       if( FT_Err_Ok == error )
2075       {
2076
2077         FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
2078
2079         FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
2080                              static_cast< float >( ftMetrics.descender ) * FROM_266,
2081                              static_cast< float >( ftMetrics.height    ) * FROM_266,
2082                              static_cast< float >( ftFace->underline_position ) * FROM_266,
2083                              static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
2084
2085         // Create the FreeType font face item to cache.
2086         FontFaceCacheItem fontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics );
2087
2088         // Set the index to the font's id cache.
2089         fontFaceCacheItem.mFontId = mFontIdCache.Count();
2090
2091         // Create the font id item to cache.
2092         FontIdCacheItem fontIdCacheItem;
2093         fontIdCacheItem.type = FontDescription::FACE_FONT;
2094
2095         // Set the index to the FreeType font face cache.
2096         fontIdCacheItem.id = mFontFaceCache.size();
2097         fontFaceId = fontIdCacheItem.id + 1u;
2098
2099         // Cache the items.
2100         mFontFaceCache.push_back( fontFaceCacheItem );
2101         mFontIdCache.PushBack( fontIdCacheItem );
2102
2103         // Set the font id to be returned.
2104         id = mFontIdCache.Count();
2105       }
2106       else
2107       {
2108         DALI_LOG_INFO( gLogFilter, Debug::General, "  FreeType Set_Char_Size error: %d for pointSize %d\n", error, requestedPointSize );
2109       }
2110     }
2111
2112     if( 0u != fontFaceId )
2113     {
2114       if( cacheDescription )
2115       {
2116         CacheFontPath( ftFace, fontFaceId, requestedPointSize, path );
2117       }
2118     }
2119   }
2120   else
2121   {
2122     DALI_LOG_INFO( gLogFilter, Debug::General, "  FreeType New_Face error: %d for [%s]\n", error, path.c_str() );
2123   }
2124
2125   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
2126   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::CreateFont\n" );
2127
2128   return id;
2129 }
2130
2131 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, unsigned int srcWidth, unsigned int srcHeight, const unsigned char* const srcBuffer )
2132 {
2133   // Set the input dimensions.
2134   const ImageDimensions inputDimensions( srcWidth, srcHeight );
2135
2136   // Set the output dimensions.
2137   // If the output dimension is not given, the input dimension is set
2138   // and won't be downscaling.
2139   data.width = ( data.width == 0 ) ? srcWidth : data.width;
2140   data.height = ( data.height == 0 ) ? srcHeight : data.height;
2141   const ImageDimensions desiredDimensions( data.width, data.height );
2142
2143   // Creates the output buffer
2144   const unsigned int bufferSize = data.width * data.height * 4u;
2145   data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
2146
2147   if( inputDimensions == desiredDimensions )
2148   {
2149     // There isn't downscaling.
2150     memcpy( data.buffer, srcBuffer, bufferSize );
2151   }
2152   else
2153   {
2154     Dali::Internal::Platform::LanczosSample4BPP( srcBuffer,
2155                                                  inputDimensions,
2156                                                  data.buffer,
2157                                                  desiredDimensions );
2158   }
2159 }
2160
2161 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap, bool isShearRequired )
2162 {
2163   if( srcBitmap.width*srcBitmap.rows > 0 )
2164   {
2165     switch( srcBitmap.pixel_mode )
2166     {
2167       case FT_PIXEL_MODE_GRAY:
2168       {
2169         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
2170         {
2171           uint8_t* pixelsIn = srcBitmap.buffer;
2172           unsigned int width = srcBitmap.width;
2173           unsigned height = srcBitmap.rows;
2174
2175           std::unique_ptr<uint8_t, void(*)(void*)> pixelsOutPtr( nullptr, free );
2176
2177           if( isShearRequired )
2178           {
2179             /**
2180              * Glyphs' bitmaps with no slant retrieved from FreeType:
2181              * __________     ____
2182              * |XXXXXXXX|     |XX|
2183              * |   XX   |     |XX|
2184              * |   XX   |     |XX|
2185              * |   XX   |     |XX|
2186              * |   XX   |     |XX|
2187              * |   XX   |     |XX|
2188              * ----------     ----
2189              *
2190              * Expected glyphs' bitmaps with italic slant:
2191              * ____________   ______
2192              * |  XXXXXXXX|   |  XX|
2193              * |     XX   |   |  XX|
2194              * |    XX    |   | XX |
2195              * |    XX    |   | XX |
2196              * |   XX     |   |XX  |
2197              * |   XX     |   |XX  |
2198              * ------------   ------
2199              *
2200              * Glyphs' bitmaps with software italic slant retrieved from FreeType:
2201              * __________     ______
2202              * |XXXXXXXX|     |  XX|
2203              * |   XX   |     |  XX|
2204              * |  XX    |     | XX |
2205              * |  XX    |     | XX |
2206              * | XX     |     |XX  |
2207              * | XX     |     |XX  |
2208              * ----------     ------
2209              *
2210              * This difference in some bitmaps' width causes an overlap of some glyphs. This is the reason why a shear operation is done here instead of relying on the experimental FT_GlyphSlot_Oblique() implementation.
2211              */
2212             unsigned int widthOut = 0u;
2213             unsigned int heightOut = 0u;
2214             uint8_t* pixelsOut = nullptr;
2215
2216             Dali::Internal::Platform::HorizontalShear( pixelsIn,
2217                                                        width,
2218                                                        height,
2219                                                        1u,
2220                                                        -TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE,
2221                                                        pixelsOut,
2222                                                        widthOut,
2223                                                        heightOut );
2224
2225             width = widthOut;
2226             height = heightOut;
2227             pixelsIn = pixelsOut;
2228             pixelsOutPtr.reset( pixelsOut );
2229           }
2230
2231           const unsigned int bufferSize = width * height;
2232           data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
2233           data.width = width;
2234           data.height = height;
2235           data.format = Pixel::L8; // Sets the pixel format.
2236           memcpy( data.buffer, pixelsIn, bufferSize );
2237         }
2238         break;
2239       }
2240
2241 #ifdef FREETYPE_BITMAP_SUPPORT
2242       case FT_PIXEL_MODE_BGRA:
2243       {
2244         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
2245         {
2246           ConvertBitmap( data, srcBitmap.width, srcBitmap.rows, srcBitmap.buffer );
2247
2248           // Sets the pixel format.
2249           data.format = Pixel::BGRA8888;
2250         }
2251         break;
2252       }
2253 #endif
2254       default:
2255       {
2256         DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::ConvertBitmap. FontClient Unable to create Bitmap of this PixelType\n" );
2257         break;
2258       }
2259     }
2260   }
2261 }
2262
2263 bool FontClient::Plugin::FindFont( const FontPath& path,
2264                                    PointSize26Dot6 requestedPointSize,
2265                                    FaceIndex faceIndex,
2266                                    FontId& fontId ) const
2267 {
2268   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
2269   DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
2270   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
2271   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of fonts in the cache : %d\n", mFontFaceCache.size() );
2272
2273   fontId = 0u;
2274   for( const auto& cacheItem : mFontFaceCache )
2275   {
2276     if( cacheItem.mRequestedPointSize == requestedPointSize &&
2277         cacheItem.mFaceIndex == faceIndex &&
2278         cacheItem.mPath == path )
2279     {
2280       fontId = cacheItem.mFontId + 1u;
2281
2282       DALI_LOG_INFO( gLogFilter, Debug::General, "  font found, id : %d\n", fontId );
2283       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
2284
2285       return true;
2286     }
2287   }
2288
2289   DALI_LOG_INFO( gLogFilter, Debug::General, "  font not found\n" );
2290   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
2291
2292   return false;
2293 }
2294
2295 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
2296                                             FontDescriptionId& validatedFontId )
2297 {
2298   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindValidatedFont\n" );
2299   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
2300   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
2301   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
2302   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
2303   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
2304   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of validated fonts in the cache : %d\n", mValidatedFontCache.size() );
2305
2306   validatedFontId = 0u;
2307
2308   for( const auto& item : mValidatedFontCache )
2309   {
2310     if( !fontDescription.family.empty() &&
2311         ( fontDescription.family == item.fontDescription.family ) &&
2312         ( fontDescription.width == item.fontDescription.width ) &&
2313         ( fontDescription.weight == item.fontDescription.weight ) &&
2314         ( fontDescription.slant == item.fontDescription.slant ) )
2315     {
2316       validatedFontId = item.index;
2317
2318       DALI_LOG_INFO( gLogFilter, Debug::General, "  validated font found, id : %d\n", validatedFontId );
2319       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
2320       return true;
2321     }
2322   }
2323
2324   DALI_LOG_INFO( gLogFilter, Debug::General, "  validated font not found\n" );
2325   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
2326   return false;
2327 }
2328
2329 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
2330                                                FontList*& fontList,
2331                                                CharacterSetList*& characterSetList )
2332 {
2333   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFontList\n" );
2334   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
2335   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
2336   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
2337   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
2338   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
2339   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of fallback font lists in the cache : %d\n", mFallbackCache.size() );
2340
2341   fontList = nullptr;
2342
2343   for( const auto& item : mFallbackCache )
2344   {
2345     if( !fontDescription.family.empty() &&
2346         ( fontDescription.family == item.fontDescription.family ) &&
2347         ( fontDescription.width == item.fontDescription.width ) &&
2348         ( fontDescription.weight == item.fontDescription.weight ) &&
2349         ( fontDescription.slant == item.fontDescription.slant ) )
2350     {
2351       fontList = item.fallbackFonts;
2352       characterSetList = item.characterSets;
2353
2354       DALI_LOG_INFO( gLogFilter, Debug::General, "  fallback font list found.\n" );
2355       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
2356       return true;
2357     }
2358   }
2359
2360   DALI_LOG_INFO( gLogFilter, Debug::General, "  fallback font list not found.\n" );
2361   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
2362   return false;
2363 }
2364
2365 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
2366                                    PointSize26Dot6 requestedPointSize,
2367                                    FontId& fontId )
2368 {
2369   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
2370   DALI_LOG_INFO( gLogFilter, Debug::General, "    validatedFontId  : %d\n", validatedFontId );
2371   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
2372
2373   fontId = 0u;
2374
2375   for( const auto& item : mFontDescriptionSizeCache )
2376   {
2377     if( ( validatedFontId == item.validatedFontId ) &&
2378         ( requestedPointSize == item.requestedPointSize ) )
2379     {
2380       fontId = item.fontId;
2381
2382       DALI_LOG_INFO( gLogFilter, Debug::General, "  font found, id : %d\n", fontId );
2383       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
2384       return true;
2385     }
2386   }
2387
2388   DALI_LOG_INFO( gLogFilter, Debug::General, "  font not found.\n" );
2389   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
2390   return false;
2391 }
2392
2393 bool FontClient::Plugin::FindBitmapFont( const FontFamily& bitmapFont, FontId& fontId ) const
2394 {
2395   fontId = 0u;
2396
2397   for( const auto& item : mBitmapFontCache )
2398   {
2399     if( bitmapFont == item.font.name )
2400     {
2401       fontId = item.id + 1u;
2402       return true;
2403     }
2404   }
2405
2406   return false;
2407 }
2408
2409 bool FontClient::Plugin::IsScalable( const FontPath& path )
2410 {
2411   bool isScalable = false;
2412
2413   FT_Face ftFace;
2414   int error = FT_New_Face( mFreeTypeLibrary,
2415                            path.c_str(),
2416                            0,
2417                            &ftFace );
2418   if( FT_Err_Ok != error )
2419   {
2420     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: %s\n", path.c_str() );
2421   }
2422   else
2423   {
2424     isScalable = ftFace->face_flags & FT_FACE_FLAG_SCALABLE;
2425   }
2426
2427   return isScalable;
2428 }
2429
2430 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
2431 {
2432   // Create a font pattern.
2433   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription ); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
2434
2435   FcResult result = FcResultMatch;
2436
2437   // match the pattern
2438   FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result ); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
2439   bool isScalable = false;
2440
2441   if( match )
2442   {
2443     // Get the path to the font file name.
2444     FontPath path;
2445     GetFcString( match, FC_FILE, path );
2446     isScalable = IsScalable( path );
2447   }
2448   else
2449   {
2450     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
2451   }
2452
2453   // Destroys the created patterns.
2454   FcPatternDestroy( match );
2455   FcPatternDestroy( fontFamilyPattern );
2456
2457   return isScalable;
2458 }
2459
2460 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
2461 {
2462   // Empty the caller container
2463   sizes.Clear();
2464
2465   FT_Face ftFace;
2466   int error = FT_New_Face( mFreeTypeLibrary,
2467                            path.c_str(),
2468                            0,
2469                            &ftFace );
2470   if( FT_Err_Ok != error )
2471   {
2472     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font path : [%s]\n", path.c_str() );
2473   }
2474
2475   // Fetch the number of fixed sizes available
2476   if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
2477   {
2478     for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
2479     {
2480       sizes.PushBack( ftFace->available_sizes[ i ].size );
2481     }
2482   }
2483 }
2484
2485 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
2486                                         Vector< PointSize26Dot6 >& sizes )
2487 {
2488   // Create a font pattern.
2489   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription ); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
2490
2491   FcResult result = FcResultMatch;
2492
2493   // match the pattern
2494   FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result ); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
2495
2496   if( match )
2497   {
2498     // Get the path to the font file name.
2499     FontPath path;
2500     GetFcString( match, FC_FILE, path );
2501     GetFixedSizes( path, sizes );
2502   }
2503   else
2504   {
2505     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
2506   }
2507
2508   // Destroys the created patterns.
2509   FcPatternDestroy( match );
2510   FcPatternDestroy( fontFamilyPattern );
2511 }
2512
2513 bool FontClient::Plugin::HasItalicStyle( FontId fontId ) const
2514 {
2515   bool hasItalicStyle = false;
2516
2517   const FontId index = fontId - 1u;
2518
2519   if( ( fontId > 0 ) &&
2520       ( index < mFontIdCache.Count() ) )
2521   {
2522     const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
2523
2524     if( FontDescription::FACE_FONT == fontIdCacheItem.type )
2525     {
2526       const FontFaceCacheItem& font = mFontFaceCache[fontIdCacheItem.id];
2527
2528       hasItalicStyle = 0u != ( font.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC );
2529     }
2530   }
2531   else
2532   {
2533     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId );
2534   }
2535
2536   return hasItalicStyle;
2537 }
2538
2539 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize,  const FontPath& path )
2540 {
2541   FontDescription description;
2542   description.path = path;
2543   description.family = std::move( FontFamily( ftFace->family_name ) );
2544   description.weight = FontWeight::NONE;
2545   description.width = FontWidth::NONE;
2546   description.slant = FontSlant::NONE;
2547
2548   // Note FreeType doesn't give too much info to build a proper font style.
2549   if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
2550   {
2551     description.slant = FontSlant::ITALIC;
2552   }
2553   if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
2554   {
2555     description.weight = FontWeight::BOLD;
2556   }
2557
2558   FontDescriptionId validatedFontId = 0u;
2559   if( !FindValidatedFont( description,
2560                           validatedFontId ) )
2561   {
2562     // Set the index to the vector of paths to font file names.
2563     validatedFontId = mFontDescriptionCache.size();
2564
2565     FcPattern* pattern = CreateFontFamilyPattern( description ); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
2566
2567     FcResult result = FcResultMatch;
2568     FcPattern* match = FcFontMatch( nullptr, pattern, &result ); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
2569
2570     FcCharSet* characterSet = nullptr;
2571     FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
2572
2573     const FontId fontFaceId = id - 1u;
2574     mFontFaceCache[fontFaceId].mCharacterSet = FcCharSetCopy( characterSet ); // Increases the reference counter.
2575
2576     // Destroys the created patterns.
2577     FcPatternDestroy( match );
2578     FcPatternDestroy( pattern );
2579
2580     // Add the path to the cache.
2581     description.type = FontDescription::FACE_FONT;
2582     mFontDescriptionCache.push_back( description );
2583
2584     // Increase the reference counter and add the character set to the cache.
2585     mCharacterSetCache.PushBack( FcCharSetCopy( characterSet ) );
2586
2587     // Cache the index and the font's description.
2588     mValidatedFontCache.push_back( std::move( FontDescriptionCacheItem( std::move( description ),
2589                                                                         validatedFontId) ) );
2590
2591     // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
2592     mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId,
2593                                                                        requestedPointSize,
2594                                                                        fontFaceId ) );
2595   }
2596 }
2597
2598 FcCharSet* FontClient::Plugin::CreateCharacterSetFromDescription( const FontDescription& description )
2599 {
2600   FcCharSet* characterSet = nullptr;
2601
2602   FcPattern* pattern = CreateFontFamilyPattern( description ); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
2603
2604   if( nullptr != pattern )
2605   {
2606     FcResult result = FcResultMatch;
2607     FcPattern* match = FcFontMatch( nullptr, pattern, &result ); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
2608
2609     FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
2610
2611     // Destroys the created patterns.
2612     FcPatternDestroy( match );
2613     FcPatternDestroy( pattern );
2614   }
2615
2616   return characterSet;
2617 }
2618
2619 void FontClient::Plugin::ClearFallbackCache( std::vector<FallbackCacheItem>& fallbackCache )
2620 {
2621   for( auto& item : fallbackCache )
2622   {
2623     if( nullptr != item.fallbackFonts )
2624     {
2625       delete item.fallbackFonts;
2626     }
2627
2628     if( nullptr != item.characterSets )
2629     {
2630       // Free the resources allocated by the FcCharSet objects in the 'characterSets' vector.
2631       DestroyCharacterSets( *item.characterSets );
2632       delete item.characterSets;
2633     }
2634   }
2635 }
2636
2637 void FontClient::Plugin::ClearCharacterSetFromFontFaceCache()
2638 {
2639   for( auto& item : mFontFaceCache )
2640   {
2641     FcCharSetDestroy( item.mCharacterSet );
2642     item.mCharacterSet = nullptr;
2643   }
2644 }
2645
2646 } // namespace Internal
2647
2648 } // namespace TextAbstraction
2649
2650 } // namespace Dali