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