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