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