Support software styling
[platform/core/uifw/dali-adaptor.git] / dali / internal / text / text-abstraction / font-client-plugin-impl.cpp
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/text/text-abstraction/font-client-plugin-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/devel-api/text-abstraction/font-list.h>
23 #include <dali/public-api/common/dali-vector.h>
24 #include <dali/public-api/common/vector-wrapper.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/integration-api/platform-abstraction.h>
27 #include <dali/internal/text/text-abstraction/font-client-helper.h>
28 #include <dali/internal/imaging/common/image-operations.h>
29 #include <dali/internal/adaptor/common/adaptor-impl.h>
30
31 // EXTERNAL INCLUDES
32 #include <fontconfig/fontconfig.h>
33
34 namespace
35 {
36
37 #if defined(DEBUG_ENABLED)
38 Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
39 #endif
40
41 /**
42  * Conversion from Fractional26.6 to float
43  */
44 const float FROM_266 = 1.0f / 64.0f;
45 const float POINTS_PER_INCH = 72.f;
46 const FT_Fixed FONT_SLANT_TANGENT = 0.221694663 * 0x10000; // For support software italic
47
48 const std::string FONT_FORMAT( "TrueType" );
49 const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
50 const int DEFAULT_FONT_WIDTH  = 100; // normal
51 const int DEFAULT_FONT_WEIGHT =  80; // normal
52 const int DEFAULT_FONT_SLANT  =   0; // normal
53
54 const uint32_t ELLIPSIS_CHARACTER = 0x2026;
55
56 // http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
57
58 // NONE            -1  --> DEFAULT_FONT_WIDTH (NORMAL) will be used.
59 // ULTRA_CONDENSED 50
60 // EXTRA_CONDENSED 63
61 // CONDENSED       75
62 // SEMI_CONDENSED  87
63 // NORMAL         100
64 // SEMI_EXPANDED  113
65 // EXPANDED       125
66 // EXTRA_EXPANDED 150
67 // ULTRA_EXPANDED 200
68 const int FONT_WIDTH_TYPE_TO_INT[] = { -1, 50, 63, 75, 87, 100, 113, 125, 150, 200 };
69 const unsigned int NUM_FONT_WIDTH_TYPE = sizeof( FONT_WIDTH_TYPE_TO_INT ) / sizeof( int );
70
71 // NONE                       -1  --> DEFAULT_FONT_WEIGHT (NORMAL) will be used.
72 // THIN                        0
73 // ULTRA_LIGHT, EXTRA_LIGHT   40
74 // LIGHT                      50
75 // DEMI_LIGHT, SEMI_LIGHT     55
76 // BOOK                       75
77 // NORMAL, REGULAR            80
78 // MEDIUM                    100
79 // DEMI_BOLD, SEMI_BOLD      180
80 // BOLD                      200
81 // ULTRA_BOLD, EXTRA_BOLD    205
82 // BLACK, HEAVY, EXTRA_BLACK 210
83 const int FONT_WEIGHT_TYPE_TO_INT[] = { -1, 0, 40, 50, 55, 75, 80, 100, 180, 200, 205, 210 };
84 const unsigned int NUM_FONT_WEIGHT_TYPE = sizeof( FONT_WEIGHT_TYPE_TO_INT ) / sizeof( int );
85
86 // NONE             -1 --> DEFAULT_FONT_SLANT (NORMAL) will be used.
87 // NORMAL, ROMAN     0
88 // ITALIC          100
89 // OBLIQUE         110
90 const int FONT_SLANT_TYPE_TO_INT[] = { -1, 0, 100, 110 };
91 const unsigned int NUM_FONT_SLANT_TYPE = sizeof( FONT_SLANT_TYPE_TO_INT ) / sizeof( int );
92
93 } // namespace
94
95 using Dali::Vector;
96
97 namespace Dali
98 {
99
100 namespace TextAbstraction
101 {
102
103 namespace Internal
104 {
105
106 /**
107  * @brief Returns the FontWidth's enum index for the given width value.
108  *
109  * @param[in] width The width value.
110  *
111  * @return The FontWidth's enum index.
112  */
113 FontWidth::Type IntToWidthType( int width )
114 {
115   return static_cast<FontWidth::Type>( ValueToIndex( width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u ) );
116 }
117
118 /**
119  * @brief Returns the FontWeight's enum index for the given weight value.
120  *
121  * @param[in] weight The weight value.
122  *
123  * @return The FontWeight's enum index.
124  */
125 FontWeight::Type IntToWeightType( int weight )
126 {
127   return static_cast<FontWeight::Type>( ValueToIndex( weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u ) );
128 }
129
130 /**
131  * @brief Returns the FontSlant's enum index for the given slant value.
132  *
133  * @param[in] slant The slant value.
134  *
135  * @return The FontSlant's enum index.
136  */
137 FontSlant::Type IntToSlantType( int slant )
138 {
139   return static_cast<FontSlant::Type>( ValueToIndex( slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u ) );
140 }
141
142 FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( FontDescription&& font, FontList* fallbackFonts, CharacterSetList* characterSets )
143 : fontDescription{ std::move( font ) },
144   fallbackFonts{ fallbackFonts },
145   characterSets{ characterSets }
146 {
147 }
148
149 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
150                                                                         FontDescriptionId index )
151 : fontDescription{ fontDescription },
152   index{ index }
153 {
154 }
155
156 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( FontDescription&& fontDescription,
157                                                                         FontDescriptionId index )
158 : fontDescription{ std::move( fontDescription ) },
159   index{ index }
160 {
161 }
162
163 FontClient::Plugin::FontDescriptionSizeCacheItem::FontDescriptionSizeCacheItem( FontDescriptionId validatedFontId,
164                                                                                 PointSize26Dot6 requestedPointSize,
165                                                                                 FontId fontId )
166 : validatedFontId( validatedFontId ),
167   requestedPointSize( requestedPointSize ),
168   fontId( fontId )
169 {
170 }
171
172 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
173                                                           const FontPath& path,
174                                                           PointSize26Dot6 requestedPointSize,
175                                                           FaceIndex face,
176                                                           const FontMetrics& metrics )
177 : mFreeTypeFace( ftFace ),
178   mPath( path ),
179   mRequestedPointSize( requestedPointSize ),
180   mFaceIndex( face ),
181   mMetrics( metrics ),
182   mCharacterSet( nullptr ),
183   mFixedWidthPixels( 0.0f ),
184   mFixedHeightPixels( 0.0f ),
185   mVectorFontId( 0 ),
186   mIsFixedSizeBitmap( false ),
187   mHasColorTables( false )
188 {
189 }
190
191 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
192                                                           const FontPath& path,
193                                                           PointSize26Dot6 requestedPointSize,
194                                                           FaceIndex face,
195                                                           const FontMetrics& metrics,
196                                                           float fixedWidth,
197                                                           float fixedHeight,
198                                                           bool hasColorTables )
199 : mFreeTypeFace( ftFace ),
200   mPath( path ),
201   mRequestedPointSize( requestedPointSize ),
202   mFaceIndex( face ),
203   mMetrics( metrics ),
204   mCharacterSet( nullptr ),
205   mFixedWidthPixels( fixedWidth ),
206   mFixedHeightPixels( fixedHeight ),
207   mVectorFontId( 0 ),
208   mIsFixedSizeBitmap( true ),
209   mHasColorTables( hasColorTables )
210 {
211 }
212
213 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
214                             unsigned int verticalDpi )
215 : mFreeTypeLibrary( nullptr ),
216   mDpiHorizontal( horizontalDpi ),
217   mDpiVertical( verticalDpi ),
218   mDefaultFontDescription(),
219   mSystemFonts(),
220   mDefaultFonts(),
221   mFontFaceCache(),
222   mValidatedFontCache(),
223   mFontDescriptionCache( 1u ),
224   mCharacterSetCache(),
225   mFontDescriptionSizeCache(),
226   mVectorFontCache( nullptr ),
227   mEllipsisCache(),
228   mDefaultFontDescriptionCached( false )
229 {
230   mCharacterSetCache.Resize( 1u );
231
232   int error = FT_Init_FreeType( &mFreeTypeLibrary );
233   if( FT_Err_Ok != error )
234   {
235     DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Init error: %d\n", error );
236   }
237
238 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
239   mVectorFontCache = new VectorFontCache( mFreeTypeLibrary );
240 #endif
241 }
242
243 FontClient::Plugin::~Plugin()
244 {
245   for( auto& item : mFallbackCache )
246   {
247     if( item.fallbackFonts )
248     {
249       delete item.fallbackFonts;
250       delete item.characterSets;
251       item.fallbackFonts = nullptr;
252       item.characterSets = nullptr;
253     }
254   }
255
256 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
257   delete mVectorFontCache;
258 #endif
259   DestroyMatchedPatterns();
260   FT_Done_FreeType( mFreeTypeLibrary );
261 }
262
263 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
264                                  unsigned int verticalDpi )
265 {
266   mDpiHorizontal = horizontalDpi;
267   mDpiVertical = verticalDpi;
268 }
269
270 void FontClient::Plugin::ResetSystemDefaults()
271 {
272   mDefaultFontDescriptionCached = false;
273 }
274
275 void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList )
276 {
277   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::SetFontList\n" );
278   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
279   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
280   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
281   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
282
283   fontList.clear();
284
285   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
286
287   FcResult result = FcResultMatch;
288
289   // Match the pattern.
290   FcFontSet* fontSet = FcFontSort( nullptr /* use default configure */,
291                                    fontFamilyPattern,
292                                    false /* don't trim */,
293                                    nullptr,
294                                    &result );
295
296   if( nullptr != fontSet )
297   {
298     DALI_LOG_INFO( gLogFilter, Debug::General, "  number of fonts found : [%d]\n", fontSet->nfont );
299     // Reserve some space to avoid reallocations.
300     fontList.reserve( fontSet->nfont );
301
302     for( int i = 0u; i < fontSet->nfont; ++i )
303     {
304       FcPattern* fontPattern = fontSet->fonts[i];
305
306       FontPath path;
307
308       // Skip fonts with no path
309       if( GetFcString( fontPattern, FC_FILE, path ) )
310       {
311         FcCharSet* characterSet = nullptr;
312         FcPatternGetCharSet( fontPattern, FC_CHARSET, 0u, &characterSet );
313
314         characterSetList.PushBack( characterSet );
315         fontList.push_back( FontDescription() );
316         FontDescription& newFontDescription = fontList.back();
317
318         newFontDescription.path = std::move( path );
319
320         int width = 0;
321         int weight = 0;
322         int slant = 0;
323         GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
324         GetFcInt( fontPattern, FC_WIDTH, width );
325         GetFcInt( fontPattern, FC_WEIGHT, weight );
326         GetFcInt( fontPattern, FC_SLANT, slant );
327         newFontDescription.width = IntToWidthType( width );
328         newFontDescription.weight = IntToWeightType( weight );
329         newFontDescription.slant = IntToSlantType( slant );
330
331         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  description; family : [%s]\n", newFontDescription.family.c_str() );
332         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", newFontDescription.path.c_str() );
333         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[newFontDescription.width] );
334         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[newFontDescription.weight] );
335         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[newFontDescription.slant] );
336       }
337     }
338
339     FcFontSetDestroy( fontSet );
340   }
341   else
342   {
343     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  No fonts found.\n" );
344   }
345
346   FcPatternDestroy( fontFamilyPattern );
347   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::SetFontList\n" );
348 }
349
350 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
351 {
352   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultFonts\n" );
353
354   if( mDefaultFonts.empty() )
355   {
356     FontDescription fontDescription;
357     fontDescription.family = DEFAULT_FONT_FAMILY_NAME;  // todo This could be set to the Platform font
358     fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
359     fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
360     fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
361     SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets );
362   }
363
364   defaultFonts = mDefaultFonts;
365
366   DALI_LOG_INFO( gLogFilter, Debug::General, "  number of default fonts : [%d]\n", mDefaultFonts.size() );
367   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultFonts\n" );
368 }
369
370 void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
371 {
372   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultPlatformFontDescription\n");
373
374   if( !mDefaultFontDescriptionCached )
375   {
376     // Clear any font config stored info in the caches.
377     mDefaultFontCharacterSets.Clear();
378     mCharacterSetCache.Clear();
379
380     for( auto& item : mFallbackCache )
381     {
382       item.characterSets->Clear();
383     }
384
385     for( auto& item : mFontFaceCache )
386     {
387       // Set the character set pointer as null. Will be created again the next time IsCharacterSupportedByFont()
388       item.mCharacterSet = nullptr;
389     }
390
391     // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
392     FcInitReinitialize();
393
394     FcPattern* matchPattern = FcPatternCreate();
395
396     if( matchPattern )
397     {
398       FcConfigSubstitute( nullptr, matchPattern, FcMatchPattern );
399       FcDefaultSubstitute( matchPattern );
400
401       FcCharSet* characterSet = nullptr;
402       MatchFontDescriptionToPattern( matchPattern, mDefaultFontDescription, &characterSet );
403       FcPatternDestroy( matchPattern );
404     }
405
406     // Create again the character sets as they are not valid after FcInitReinitialize()
407
408     for( const auto& description : mDefaultFonts )
409     {
410       mDefaultFontCharacterSets.PushBack( CreateCharacterSetFromDescription( description ) );
411     }
412
413     for( const auto& description : mFontDescriptionCache )
414     {
415       mCharacterSetCache.PushBack( CreateCharacterSetFromDescription( description ) );
416     }
417
418     for( auto& item : mFallbackCache )
419     {
420       if( nullptr != item.fallbackFonts )
421       {
422         if( nullptr == item.characterSets )
423         {
424           item.characterSets = new CharacterSetList;
425         }
426
427         for( const auto& description : *( item.fallbackFonts ) )
428         {
429           item.characterSets->PushBack( CreateCharacterSetFromDescription( description ) );
430         }
431       }
432     }
433
434     mDefaultFontDescriptionCached = true;
435   }
436
437   fontDescription.path   = mDefaultFontDescription.path;
438   fontDescription.family = mDefaultFontDescription.family;
439   fontDescription.width  = mDefaultFontDescription.width;
440   fontDescription.weight = mDefaultFontDescription.weight;
441   fontDescription.slant  = mDefaultFontDescription.slant;
442
443   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
444   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
445   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
446   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
447   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
448   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultPlatformFontDescription\n");
449 }
450
451 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
452 {
453   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetSystemFonts\n");
454
455   if( mSystemFonts.empty() )
456   {
457     InitSystemFonts();
458   }
459
460   systemFonts = mSystemFonts;
461   DALI_LOG_INFO( gLogFilter, Debug::General, "  number of system fonts : [%d]\n", mSystemFonts.size() );
462   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetSystemFonts\n");
463 }
464
465 void FontClient::Plugin::GetDescription( FontId id,
466                                          FontDescription& fontDescription ) const
467 {
468   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDescription\n");
469   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
470
471   for( const auto& item : mFontDescriptionSizeCache )
472   {
473     if( item.fontId == id )
474     {
475       fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
476
477       DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
478       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
479       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
480       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
481       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
482       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
483       return;
484     }
485   }
486
487   DALI_LOG_INFO( gLogFilter, Debug::General, "  No description found for the font ID %d\n", id );
488   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
489 }
490
491 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
492 {
493   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetPointSize\n");
494   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
495   const FontId index = id - 1u;
496
497   if( ( id > 0u ) &&
498       ( index < mFontFaceCache.size() ) )
499   {
500     DALI_LOG_INFO( gLogFilter, Debug::General, "  point size : %d\n", ( *( mFontFaceCache.begin() + index ) ).mRequestedPointSize );
501     DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
502     return ( *( mFontFaceCache.begin() + index ) ).mRequestedPointSize;
503   }
504   else
505   {
506     DALI_LOG_INFO( gLogFilter, Debug::General, "  Invalid font ID %d\n", id );
507   }
508
509   DALI_LOG_INFO( gLogFilter, Debug::General, "  default point size : %d\n", TextAbstraction::FontClient::DEFAULT_POINT_SIZE );
510   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
511   return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
512 }
513
514 bool FontClient::Plugin::IsCharacterSupportedByFont( FontId fontId, Character character )
515 {
516   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::IsCharacterSupportedByFont\n");
517   DALI_LOG_INFO( gLogFilter, Debug::General, "    font id : %d\n", fontId );
518   DALI_LOG_INFO( gLogFilter, Debug::General, "  character : %p\n", character );
519
520   if( ( fontId < 1u ) || ( fontId > mFontFaceCache.size() ) )
521   {
522     DALI_LOG_INFO( gLogFilter, Debug::General, "  Invalid font id. Number of items in the cache: %d\n",mFontFaceCache.size());
523     DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
524     return false;
525   }
526
527   --fontId;
528
529   bool isSupported = false;
530
531   FontFaceCacheItem& cacheItem = mFontFaceCache[fontId];
532
533   if( nullptr == cacheItem.mCharacterSet )
534   {
535     // Create again the character set.
536     // It can be null if the ResetSystemDefaults() method has been called.
537
538     FontDescription description;
539     description.path = cacheItem.mPath;
540     description.family = std::move( FontFamily( cacheItem.mFreeTypeFace->family_name ) );
541     description.weight = FontWeight::NONE;
542     description.width = FontWidth::NONE;
543     description.slant = FontSlant::NONE;
544
545     // Note FreeType doesn't give too much info to build a proper font style.
546     if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC )
547     {
548       description.slant = FontSlant::ITALIC;
549     }
550     if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_BOLD )
551     {
552       description.weight = FontWeight::BOLD;
553     }
554
555     cacheItem.mCharacterSet = CreateCharacterSetFromDescription( description );
556   }
557
558   isSupported = FcCharSetHasChar( cacheItem.mCharacterSet, character );
559
560   DALI_LOG_INFO( gLogFilter, Debug::General, "  is supported : %s\n", (isSupported ? "true" : "false") );
561   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
562   return isSupported;
563 }
564
565 FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList,
566                                                  const CharacterSetList& characterSetList,
567                                                  Character character,
568                                                  PointSize26Dot6 requestedPointSize,
569                                                  bool preferColor )
570 {
571   DALI_ASSERT_DEBUG( ( fontList.size() == characterSetList.Count() ) && "FontClient::Plugin::FindFontForCharacter. Different number of fonts and character sets." );
572
573   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFontForCharacter\n" );
574   DALI_LOG_INFO( gLogFilter, Debug::General, "           character : %p\n", character );
575   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
576   DALI_LOG_INFO( gLogFilter, Debug::General, "         preferColor : %s\n", ( preferColor ? "true" : "false" ) );
577
578   FontId fontId = 0u;
579   bool foundColor = false;
580
581   DALI_LOG_INFO( gLogFilter, Debug::General, "  number of fonts : %d\n", fontList.size() );
582
583   // Traverse the list of fonts.
584   // Check for each font if supports the character.
585   for( unsigned int index = 0u, numberOfFonts = fontList.size(); index < numberOfFonts; ++index )
586   {
587     const FontDescription& description = fontList[index];
588     const FcCharSet* const characterSet = characterSetList[index];
589
590     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  description; family : [%s]\n", description.family.c_str() );
591     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", description.path.c_str() );
592     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[description.width] );
593     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[description.weight] );
594     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[description.slant] );
595
596     bool foundInRanges = false;
597     if( nullptr != characterSet )
598     {
599       foundInRanges = FcCharSetHasChar( characterSet, character );
600     }
601
602     if( foundInRanges )
603     {
604       fontId = GetFontId( description,
605                           requestedPointSize,
606                           0u );
607
608       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "     font id : %d\n", fontId );
609
610       if( preferColor )
611       {
612         if( ( fontId > 0 ) &&
613             ( fontId - 1u < mFontFaceCache.size() ) )
614         {
615           const FontFaceCacheItem& item = mFontFaceCache[fontId - 1u];
616
617           foundColor = item.mHasColorTables;
618         }
619
620         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  foundColor : %s\n", ( foundColor ? "true" : "false" ) );
621       }
622
623       // Keep going unless we prefer a different (color) font.
624       if( !preferColor || foundColor )
625       {
626         break;
627       }
628     }
629   }
630
631   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", fontId );
632   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFontForCharacter\n" );
633   return fontId;
634 }
635
636 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
637                                             PointSize26Dot6 requestedPointSize,
638                                             bool preferColor )
639 {
640   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindDefaultFont\n" );
641   DALI_LOG_INFO( gLogFilter, Debug::General, "           character : %p\n", charcode );
642   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
643   DALI_LOG_INFO( gLogFilter, Debug::General, "         preferColor : %s\n", ( preferColor ? "true" : "false" ) );
644
645   FontId fontId(0);
646
647   // Create the list of default fonts if it has not been created.
648   if( mDefaultFonts.empty() )
649   {
650     FontDescription fontDescription;
651     fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
652     fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
653     fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
654     fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
655
656     SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets );
657   }
658   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of default fonts : %d\n", mDefaultFonts.size() );
659
660
661   // Traverse the list of default fonts.
662   // Check for each default font if supports the character.
663   fontId = FindFontForCharacter( mDefaultFonts, mDefaultFontCharacterSets, charcode, requestedPointSize, preferColor );
664
665   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", fontId );
666   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindDefaultFont\n" );
667
668   return fontId;
669 }
670
671 FontId FontClient::Plugin::FindFallbackFont( Character charcode,
672                                              const FontDescription& preferredFontDescription,
673                                              PointSize26Dot6 requestedPointSize,
674                                              bool preferColor )
675 {
676   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFont\n" );
677   DALI_LOG_INFO( gLogFilter, Debug::General, "           character : %p\n", charcode );
678   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
679   DALI_LOG_INFO( gLogFilter, Debug::General, "         preferColor : %s\n", ( preferColor ? "true" : "false" ) );
680
681   // The font id to be returned.
682   FontId fontId = 0u;
683
684   FontDescription fontDescription;
685
686   // Fill the font description with the preferred font description and complete with the defaults.
687   fontDescription.family = preferredFontDescription.family.empty() ? DEFAULT_FONT_FAMILY_NAME : preferredFontDescription.family;
688   fontDescription.weight = ( ( FontWeight::NONE == preferredFontDescription.weight ) ? IntToWeightType( DEFAULT_FONT_WEIGHT ) : preferredFontDescription.weight );
689   fontDescription.width = ( ( FontWidth::NONE == preferredFontDescription.width ) ? IntToWidthType( DEFAULT_FONT_WIDTH ) : preferredFontDescription.width );
690   fontDescription.slant = ( ( FontSlant::NONE == preferredFontDescription.slant ) ? IntToSlantType( DEFAULT_FONT_SLANT ) : preferredFontDescription.slant );
691
692   DALI_LOG_INFO( gLogFilter, Debug::General, "  preferredFontDescription --> fontDescription\n" );
693   DALI_LOG_INFO( gLogFilter, Debug::General, "  [%s] --> [%s]\n", preferredFontDescription.family.c_str(), fontDescription.family.c_str() );
694   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  [%s] --> [%s]\n", FontWeight::Name[preferredFontDescription.weight], FontWeight::Name[fontDescription.weight] );
695   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  [%s] --> [%s]\n", FontWidth::Name[preferredFontDescription.width], FontWidth::Name[fontDescription.width] );
696   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  [%s] --> [%s]\n", FontSlant::Name[preferredFontDescription.slant], FontSlant::Name[fontDescription.slant] );
697
698   // Check first if the font's description has been queried before.
699   FontList* fontList = nullptr;
700   CharacterSetList* characterSetList = nullptr;
701
702   if( !FindFallbackFontList( fontDescription, fontList, characterSetList ) )
703   {
704     fontList = new FontList;
705     characterSetList = new CharacterSetList;
706
707     SetFontList( fontDescription, *fontList, *characterSetList );
708
709     // Add the font-list to the cache.
710     mFallbackCache.push_back( std::move( FallbackCacheItem( std::move( fontDescription ), fontList, characterSetList ) ) );
711   }
712
713   if( fontList && characterSetList )
714   {
715     fontId = FindFontForCharacter( *fontList, *characterSetList, charcode, requestedPointSize, preferColor );
716   }
717
718   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", fontId );
719   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFont\n");
720   return fontId;
721 }
722
723 FontId FontClient::Plugin::GetFontId( const FontPath& path,
724                                       PointSize26Dot6 requestedPointSize,
725                                       FaceIndex faceIndex,
726                                       bool cacheDescription )
727 {
728   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" );
729   DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
730   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
731
732   FontId id( 0 );
733
734   if( nullptr != mFreeTypeLibrary )
735   {
736     FontId foundId(0);
737     if( FindFont( path, requestedPointSize, faceIndex, foundId ) )
738     {
739       id = foundId;
740     }
741     else
742     {
743       id = CreateFont( path, requestedPointSize, faceIndex, cacheDescription );
744     }
745   }
746
747   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
748   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" );
749
750   return id;
751 }
752
753 FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
754                                       PointSize26Dot6 requestedPointSize,
755                                       FaceIndex faceIndex )
756 {
757   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" );
758   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
759   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
760   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
761   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
762   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
763   DALI_LOG_INFO( gLogFilter, Debug::General, "   requestedPointSize : %d\n", requestedPointSize );
764
765   // This method uses three vectors which caches:
766   // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
767   // * The path to font file names.
768   // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
769
770   // 1) Checks in the cache if the font's description has been validated before.
771   //    If it was it gets an index to the vector with paths to font file names. Otherwise,
772   //    retrieves using font config a path to a font file name which matches with the
773   //    font's description. The path is stored in the cache.
774   //
775   // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
776   //    font file names' exists. If exists, it gets the font id. If it doesn't it calls
777   //    the GetFontId() method with the path to the font file name and the point size to
778   //    get the font id.
779
780   // The font id to be returned.
781   FontId fontId = 0u;
782
783   // Check first if the font's description have been validated before.
784   FontDescriptionId validatedFontId = 0u;
785
786   if( !FindValidatedFont( fontDescription,
787                           validatedFontId ) )
788   {
789     // Use font config to validate the font's description.
790     ValidateFont( fontDescription,
791                   validatedFontId );
792   }
793
794   // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
795   if( !FindFont( validatedFontId, requestedPointSize, fontId ) )
796   {
797     // Retrieve the font file name path.
798     const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
799
800     // Retrieve the font id. Do not cache the description as it has been already cached.
801     fontId = GetFontId( description.path,
802                         requestedPointSize,
803                         faceIndex,
804                         false );
805
806     mFontFaceCache[fontId-1u].mCharacterSet = mCharacterSetCache[validatedFontId];
807
808     // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
809     mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId,
810                                                                        requestedPointSize,
811                                                                        fontId ) );
812   }
813
814   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", fontId );
815   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" );
816
817   return fontId;
818 }
819
820 void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
821                                        FontDescriptionId& validatedFontId )
822 {
823   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::ValidateFont\n" );
824   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
825   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
826   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
827   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
828   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
829
830   // Create a font pattern.
831   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
832
833   FontDescription description;
834
835   FcCharSet* characterSet = nullptr;
836   bool matched = MatchFontDescriptionToPattern( fontFamilyPattern, description, &characterSet );
837   FcPatternDestroy( fontFamilyPattern );
838
839   if( matched && ( nullptr != characterSet ) )
840   {
841     // Set the index to the vector of paths to font file names.
842     validatedFontId = mFontDescriptionCache.size();
843
844     DALI_LOG_INFO( gLogFilter, Debug::General, "  matched description; family : [%s]\n", description.family.c_str() );
845     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                         path : [%s]\n", description.path.c_str() );
846     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                        width : [%s]\n", FontWidth::Name[description.width] );
847     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                       weight : [%s]\n", FontWeight::Name[description.weight] );
848     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                        slant : [%s]\n\n", FontSlant::Name[description.slant] );
849     DALI_LOG_INFO( gLogFilter, Debug::General, "  validatedFontId : %d\n", validatedFontId );
850
851     // Add the path to the cache.
852     mFontDescriptionCache.push_back( description );
853     mCharacterSetCache.PushBack( characterSet );
854
855     // Cache the index and the matched font's description.
856     FontDescriptionCacheItem item( description,
857                                    validatedFontId );
858
859     mValidatedFontCache.push_back( std::move( item ) );
860
861     if( ( fontDescription.family != description.family ) ||
862         ( fontDescription.width != description.width )   ||
863         ( fontDescription.weight != description.weight ) ||
864         ( fontDescription.slant != description.slant ) )
865     {
866       // Cache the given font's description if it's different than the matched.
867       FontDescriptionCacheItem item( fontDescription,
868                                      validatedFontId );
869
870       mValidatedFontCache.push_back( std::move( item ) );
871     }
872   }
873   else
874   {
875     DALI_LOG_INFO( gLogFilter, Debug::General, "  font validation failed for font [%s]\n", fontDescription.family.c_str() );
876   }
877
878   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::ValidateFont\n" );
879 }
880
881 void FontClient::Plugin::GetFontMetrics( FontId fontId,
882                                          FontMetrics& metrics )
883 {
884   if( ( fontId > 0 ) &&
885       ( fontId - 1u < mFontFaceCache.size() ) )
886   {
887     const FontFaceCacheItem& font = mFontFaceCache[fontId-1];
888
889     metrics = font.mMetrics;
890
891     // Adjust the metrics if the fixed-size font should be down-scaled
892     if( font.mIsFixedSizeBitmap )
893     {
894       const float desiredFixedSize =  static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
895
896       if( desiredFixedSize > 0.f )
897       {
898         const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
899
900         metrics.ascender = floorf( metrics.ascender * scaleFactor );
901         metrics.descender = floorf( metrics.descender * scaleFactor );
902         metrics.height = floorf( metrics.height * scaleFactor );
903         metrics.underlinePosition = floorf( metrics.underlinePosition * scaleFactor );
904         metrics.underlineThickness = floorf( metrics.underlineThickness * scaleFactor );
905       }
906     }
907   }
908   else
909   {
910     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId );
911   }
912 }
913
914 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
915                                               Character charcode )
916 {
917   GlyphIndex index = 0u;
918
919   if( ( fontId > 0u ) &&
920       ( fontId - 1u < mFontFaceCache.size() ) )
921   {
922     FT_Face ftFace = mFontFaceCache[fontId-1u].mFreeTypeFace;
923
924     index = FT_Get_Char_Index( ftFace, charcode );
925   }
926
927   return index;
928 }
929
930 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
931                                           uint32_t size,
932                                           GlyphType type,
933                                           bool horizontal )
934 {
935   if( VECTOR_GLYPH == type )
936   {
937     return GetVectorMetrics( array, size, horizontal );
938   }
939
940   return GetBitmapMetrics( array, size, horizontal );
941 }
942
943 bool FontClient::Plugin::GetBitmapMetrics( GlyphInfo* array,
944                                            uint32_t size,
945                                            bool horizontal )
946 {
947   bool success( true );
948
949   for( unsigned int i=0; i<size; ++i )
950   {
951     GlyphInfo& glyph = array[i];
952
953     FontId fontId = glyph.fontId;
954
955     if( fontId > 0 &&
956         fontId-1 < mFontFaceCache.size() )
957     {
958       const FontFaceCacheItem& font = mFontFaceCache[fontId-1];
959
960       FT_Face ftFace = font.mFreeTypeFace;
961
962 #ifdef FREETYPE_BITMAP_SUPPORT
963       // Check to see if we should be loading a Fixed Size bitmap?
964       if ( font.mIsFixedSizeBitmap )
965       {
966         int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_COLOR );
967         if ( FT_Err_Ok == error )
968         {
969           glyph.width = font.mFixedWidthPixels;
970           glyph.height = font.mFixedHeightPixels;
971           glyph.advance = font.mFixedWidthPixels;
972           glyph.xBearing = 0.0f;
973           glyph.yBearing = font.mFixedHeightPixels;
974
975           // Adjust the metrics if the fixed-size font should be down-scaled
976           const float desiredFixedSize =  static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
977
978           if( desiredFixedSize > 0.f )
979           {
980             const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
981
982             glyph.width = floorf( glyph.width * scaleFactor );
983             glyph.height = floorf( glyph.height * scaleFactor );
984             glyph.advance = floorf( glyph.advance * scaleFactor );
985             glyph.xBearing = floorf( glyph.xBearing * scaleFactor );
986             glyph.yBearing = floorf( glyph.yBearing * scaleFactor );
987
988             glyph.scaleFactor = scaleFactor;
989           }
990         }
991         else
992         {
993           DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetBitmapMetrics. FreeType Bitmap Load_Glyph error %d\n", error );
994           success = false;
995         }
996       }
997       else
998 #endif
999       {
1000         int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_NO_AUTOHINT );
1001
1002         if( FT_Err_Ok == error )
1003         {
1004           glyph.width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
1005           glyph.height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
1006           if( horizontal )
1007           {
1008             glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
1009             glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
1010           }
1011           else
1012           {
1013             glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
1014             glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
1015           }
1016         }
1017         else
1018         {
1019           success = false;
1020         }
1021       }
1022     }
1023     else
1024     {
1025       success = false;
1026     }
1027   }
1028
1029   return success;
1030 }
1031
1032 bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array,
1033                                            uint32_t size,
1034                                            bool horizontal )
1035 {
1036 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
1037   bool success( true );
1038
1039   for( unsigned int i=0; i<size; ++i )
1040   {
1041     FontId fontId = array[i].fontId;
1042
1043     if( fontId > 0 &&
1044         fontId-1 < mFontFaceCache.size() )
1045     {
1046       FontFaceCacheItem& font = mFontFaceCache[fontId-1];
1047
1048       if( ! font.mVectorFontId )
1049       {
1050         font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
1051       }
1052
1053       mVectorFontCache->GetGlyphMetrics( font.mVectorFontId, array[i] );
1054
1055       // Vector metrics are in EMs, convert to pixels
1056       const float scale = ( static_cast<float>( font.mRequestedPointSize ) * FROM_266 ) * static_cast<float>( mDpiVertical ) / POINTS_PER_INCH;
1057       array[i].width    *= scale;
1058       array[i].height   *= scale;
1059       array[i].xBearing *= scale;
1060       array[i].yBearing *= scale;
1061       array[i].advance  *= scale;
1062     }
1063     else
1064     {
1065       success = false;
1066     }
1067   }
1068
1069   return success;
1070 #else
1071   return false;
1072 #endif
1073 }
1074
1075 void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool softwareItalic, bool softwareBold, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
1076 {
1077   if( ( fontId > 0 ) &&
1078       ( fontId - 1u < mFontFaceCache.size() ) )
1079   {
1080     FT_Face ftFace = mFontFaceCache[fontId - 1u].mFreeTypeFace;
1081
1082     FT_Error error;
1083
1084 #ifdef FREETYPE_BITMAP_SUPPORT
1085     // Check to see if this is fixed size bitmap
1086     if ( mFontFaceCache[fontId - 1u].mIsFixedSizeBitmap )
1087     {
1088       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1089     }
1090     else
1091 #endif
1092     {
1093       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_NO_AUTOHINT );
1094     }
1095     if( FT_Err_Ok == error )
1096     {
1097       FT_Glyph glyph;
1098
1099       if( softwareBold )
1100       {
1101         FT_GlyphSlot_Embolden(ftFace->glyph);
1102       }
1103
1104       if( softwareItalic )
1105       {
1106         // FT Matrix uses 16.16 fixed-point format
1107         FT_Matrix transform = {0x10000, FONT_SLANT_TANGENT, 0x00000, 0x10000};
1108         FT_Outline_Transform(&ftFace->glyph->outline, &transform);
1109       }
1110
1111       error = FT_Get_Glyph( ftFace->glyph, &glyph );
1112
1113       // Convert to bitmap if necessary
1114       if ( FT_Err_Ok == error )
1115       {
1116         if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
1117         {
1118           // Check whether we should create a bitmap for the outline
1119           if( glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0 )
1120           {
1121             // Set up a stroker
1122             FT_Stroker stroker;
1123             error = FT_Stroker_New(mFreeTypeLibrary, &stroker );
1124
1125             if ( FT_Err_Ok == error )
1126             {
1127               FT_Stroker_Set( stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0 );
1128               error = FT_Glyph_StrokeBorder( &glyph, stroker, 0, 1 );
1129
1130               if ( FT_Err_Ok == error )
1131               {
1132                 FT_Stroker_Done( stroker );
1133               }
1134               else
1135               {
1136                 DALI_LOG_ERROR( "FT_Glyph_StrokeBorder Failed with error: %d\n", error );
1137               }
1138             }
1139             else
1140             {
1141               DALI_LOG_ERROR( "FT_Stroker_New Failed with error: %d\n", error );
1142             }
1143           }
1144
1145           error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
1146           if ( FT_Err_Ok == error )
1147           {
1148             FT_BitmapGlyph bitmapGlyph = reinterpret_cast< FT_BitmapGlyph >( glyph );
1149             ConvertBitmap( data, bitmapGlyph->bitmap );
1150           }
1151           else
1152           {
1153             DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Get_Glyph Failed with error: %d\n", error );
1154           }
1155         }
1156         else
1157         {
1158           ConvertBitmap( data, ftFace->glyph->bitmap );
1159         }
1160
1161         // Created FT_Glyph object must be released with FT_Done_Glyph
1162         FT_Done_Glyph( glyph );
1163       }
1164     }
1165     else
1166     {
1167       DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Load_Glyph Failed with error: %d\n", error );
1168     }
1169   }
1170 }
1171
1172 PixelData FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
1173 {
1174   TextAbstraction::FontClient::GlyphBufferData data;
1175
1176   CreateBitmap( fontId, glyphIndex, false, false, data, outlineWidth );
1177
1178   return PixelData::New( data.buffer,
1179                          data.width * data.height * Pixel::GetBytesPerPixel( data.format ),
1180                          data.width,
1181                          data.height,
1182                          data.format,
1183                          PixelData::DELETE_ARRAY );
1184 }
1185
1186 void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
1187 {
1188   blob = nullptr;
1189   blobLength = 0;
1190
1191 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
1192   if( fontId > 0 &&
1193       fontId-1 < mFontFaceCache.size() )
1194   {
1195     FontFaceCacheItem& font = mFontFaceCache[fontId-1];
1196
1197     if( ! font.mVectorFontId )
1198     {
1199       font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
1200     }
1201
1202     mVectorFontCache->GetVectorBlob( font.mVectorFontId, fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
1203   }
1204 #endif
1205 }
1206
1207 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize )
1208 {
1209   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetEllipsisGlyph\n" );
1210   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize %d.\n", requestedPointSize );
1211
1212   // First look into the cache if there is an ellipsis glyph for the requested point size.
1213   for( const auto& item : mEllipsisCache )
1214   {
1215     if( fabsf( item.requestedPointSize - requestedPointSize ) < Math::MACHINE_EPSILON_1000 )
1216     {
1217       // Use the glyph in the cache.
1218
1219       DALI_LOG_INFO( gLogFilter, Debug::General, "  glyph id %d found in the cache.\n", item.glyph.index );
1220       DALI_LOG_INFO( gLogFilter, Debug::General, "      font %d.\n", item.glyph.fontId );
1221       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
1222
1223       return item.glyph;
1224     }
1225   }
1226
1227   // No glyph has been found. Create one.
1228   mEllipsisCache.PushBack( EllipsisItem() );
1229   EllipsisItem& item = *( mEllipsisCache.End() - 1u );
1230
1231   item.requestedPointSize = requestedPointSize;
1232
1233   // Find a font for the ellipsis glyph.
1234   item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
1235                                        requestedPointSize,
1236                                        false );
1237
1238   // Set the character index to access the glyph inside the font.
1239   item.glyph.index = FT_Get_Char_Index( mFontFaceCache[item.glyph.fontId-1].mFreeTypeFace,
1240                                         ELLIPSIS_CHARACTER );
1241
1242   GetBitmapMetrics( &item.glyph, 1u, true );
1243
1244   DALI_LOG_INFO( gLogFilter, Debug::General, "  glyph id %d found in the cache.\n", item.glyph.index );
1245   DALI_LOG_INFO( gLogFilter, Debug::General, "      font %d.\n", item.glyph.fontId );
1246   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
1247
1248   return item.glyph;
1249 }
1250
1251 bool FontClient::Plugin::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
1252 {
1253   FT_Error error = -1;
1254
1255 #ifdef FREETYPE_BITMAP_SUPPORT
1256   if( ( fontId > 0 ) &&
1257       ( fontId - 1u < mFontFaceCache.size() ) )
1258   {
1259     const FontFaceCacheItem& item = mFontFaceCache[fontId - 1u];
1260     FT_Face ftFace = item.mFreeTypeFace;
1261
1262     // Check to see if this is fixed size bitmap
1263     if( item.mHasColorTables )
1264     {
1265       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1266     }
1267   }
1268 #endif
1269
1270   return FT_Err_Ok == error;
1271 }
1272
1273 void FontClient::Plugin::InitSystemFonts()
1274 {
1275   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::InitSystemFonts\n" );
1276
1277   FcFontSet* fontSet = GetFcFontSet();
1278
1279   if( fontSet )
1280   {
1281     DALI_LOG_INFO( gLogFilter, Debug::General, "  number of system fonts : %d\n", fontSet->nfont );
1282
1283     // Reserve some space to avoid reallocations.
1284     mSystemFonts.reserve( fontSet->nfont );
1285
1286     for( int i = 0u; i < fontSet->nfont; ++i )
1287     {
1288       FcPattern* fontPattern = fontSet->fonts[i];
1289
1290       FontPath path;
1291
1292       // Skip fonts with no path
1293       if( GetFcString( fontPattern, FC_FILE, path ) )
1294       {
1295         mSystemFonts.push_back( FontDescription() );
1296         FontDescription& fontDescription = mSystemFonts.back();
1297
1298         fontDescription.path = std::move( path );
1299
1300         int width = 0;
1301         int weight = 0;
1302         int slant = 0;
1303         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
1304         GetFcInt( fontPattern, FC_WIDTH, width );
1305         GetFcInt( fontPattern, FC_WEIGHT, weight );
1306         GetFcInt( fontPattern, FC_SLANT, slant );
1307         fontDescription.width = IntToWidthType( width );
1308         fontDescription.weight = IntToWeightType( weight );
1309         fontDescription.slant = IntToSlantType( slant );
1310
1311         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  description; family : [%s]\n", fontDescription.family.c_str() );
1312         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1313         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1314         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1315         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1316       }
1317     }
1318
1319     FcFontSetDestroy( fontSet );
1320   }
1321   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::InitSystemFonts\n" );
1322 }
1323
1324 bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet )
1325 {
1326   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1327
1328   FcResult result = FcResultMatch;
1329   FcPattern* match = FcFontMatch( nullptr /* use default configure */, pattern, &result );
1330
1331   const bool matched = nullptr != match;
1332   DALI_LOG_INFO( gLogFilter, Debug::General, "  pattern matched : %s\n", ( matched ? "true" : "false" ) );
1333
1334   if( matched )
1335   {
1336     int width = 0;
1337     int weight = 0;
1338     int slant = 0;
1339     GetFcString( match, FC_FILE, fontDescription.path );
1340     GetFcString( match, FC_FAMILY, fontDescription.family );
1341     GetFcInt( match, FC_WIDTH, width );
1342     GetFcInt( match, FC_WEIGHT, weight );
1343     GetFcInt( match, FC_SLANT, slant );
1344     fontDescription.width = IntToWidthType( width );
1345     fontDescription.weight = IntToWeightType( weight );
1346     fontDescription.slant = IntToSlantType( slant );
1347
1348     // Cache the character ranges.
1349     FcPatternGetCharSet( match, FC_CHARSET, 0u, characterSet );
1350
1351     // destroyed the matched pattern
1352     FcPatternDestroy( match );
1353
1354     DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1355     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1356     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1357     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1358     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1359   }
1360
1361   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1362   return matched;
1363 }
1364
1365 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription ) const
1366 {
1367   // create the cached font family lookup pattern
1368   // a pattern holds a set of names, each name refers to a property of the font
1369   FcPattern* fontFamilyPattern = FcPatternCreate();
1370
1371   if( !fontFamilyPattern )
1372   {
1373     return nullptr;
1374   }
1375
1376   // add a property to the pattern for the font family
1377   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
1378
1379   int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
1380   if( width < 0 )
1381   {
1382     // Use default.
1383     width = DEFAULT_FONT_WIDTH;
1384   }
1385
1386   int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
1387   if( weight < 0 )
1388   {
1389     // Use default.
1390     weight = DEFAULT_FONT_WEIGHT;
1391   }
1392
1393   int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
1394   if( slant < 0 )
1395   {
1396     // Use default.
1397     slant = DEFAULT_FONT_SLANT;
1398   }
1399
1400   FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
1401   FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
1402   FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
1403
1404   // Add a property of the pattern, to say we want to match TrueType fonts
1405   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
1406
1407   // modify the config, with the mFontFamilyPatterm
1408   FcConfigSubstitute( nullptr /* use default configure */, fontFamilyPattern, FcMatchPattern );
1409
1410   // provide default values for unspecified properties in the font pattern
1411   // e.g. patterns without a specified style or weight are set to Medium
1412   FcDefaultSubstitute( fontFamilyPattern );
1413
1414   return fontFamilyPattern;
1415 }
1416
1417 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
1418 {
1419   // create a new pattern.
1420   // a pattern holds a set of names, each name refers to a property of the font
1421   FcPattern* pattern = FcPatternCreate();
1422
1423   FcFontSet* fontset = NULL;
1424
1425   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
1426   FcObjectSet* objectSet = FcObjectSetCreate();
1427
1428   if( objectSet )
1429   {
1430     // build an object set from a list of property names
1431     FcObjectSetAdd( objectSet, FC_FILE );
1432     FcObjectSetAdd( objectSet, FC_FAMILY );
1433     FcObjectSetAdd( objectSet, FC_WIDTH );
1434     FcObjectSetAdd( objectSet, FC_WEIGHT );
1435     FcObjectSetAdd( objectSet, FC_SLANT );
1436
1437     // get a list of fonts
1438     // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
1439     fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
1440
1441     // clear up the object set
1442     FcObjectSetDestroy( objectSet );
1443   }
1444   // clear up the pattern
1445   if( pattern )
1446   {
1447     FcPatternDestroy( pattern );
1448   }
1449
1450   return fontset;
1451 }
1452
1453 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1454                                       const char* const n,
1455                                       std::string& string )
1456 {
1457   FcChar8* file = nullptr;
1458   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1459
1460   if( FcResultMatch == retVal )
1461   {
1462     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1463     string.assign( reinterpret_cast<const char*>( file ) );
1464
1465     return true;
1466   }
1467
1468   return false;
1469 }
1470
1471 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
1472 {
1473   const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
1474
1475   if( FcResultMatch == retVal )
1476   {
1477     return true;
1478   }
1479
1480   return false;
1481 }
1482
1483 FontId FontClient::Plugin::CreateFont( const FontPath& path,
1484                                        PointSize26Dot6 requestedPointSize,
1485                                        FaceIndex faceIndex,
1486                                        bool cacheDescription )
1487 {
1488   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::CreateFont\n" );
1489   DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
1490   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1491
1492   FontId id = 0u;
1493
1494   // Create & cache new font face
1495   FT_Face ftFace;
1496   int error = FT_New_Face( mFreeTypeLibrary,
1497                            path.c_str(),
1498                            0,
1499                            &ftFace );
1500
1501   if( FT_Err_Ok == error )
1502   {
1503     // Check if a font is scalable.
1504     const bool isScalable = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_SCALABLE ) );
1505     const bool hasFixedSizedBitmaps = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_FIXED_SIZES ) ) && ( 0 != ftFace->num_fixed_sizes );
1506     const bool hasColorTables = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_COLOR ) );
1507
1508     DALI_LOG_INFO( gLogFilter, Debug::General, "            isScalable : [%s]\n", ( isScalable ? "true" : "false" ) );
1509     DALI_LOG_INFO( gLogFilter, Debug::General, "  hasFixedSizedBitmaps : [%s]\n", ( hasFixedSizedBitmaps ? "true" : "false" ) );
1510     DALI_LOG_INFO( gLogFilter, Debug::General, "        hasColorTables : [%s]\n", ( hasColorTables ? "true" : "false" ) );
1511
1512     // Check to see if the font contains fixed sizes?
1513     if( !isScalable && hasFixedSizedBitmaps )
1514     {
1515       PointSize26Dot6 actualPointSize = 0u;
1516       int fixedSizeIndex = 0;
1517       for( ; fixedSizeIndex < ftFace->num_fixed_sizes; ++fixedSizeIndex )
1518       {
1519         const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size;
1520         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  size index : %d, size : %d\n", fixedSizeIndex, fixedSize );
1521
1522         if( fixedSize >= requestedPointSize )
1523         {
1524           actualPointSize = fixedSize;
1525           break;
1526         }
1527       }
1528
1529       if( 0u == actualPointSize )
1530       {
1531         // The requested point size is bigger than the bigest fixed size.
1532         fixedSizeIndex = ftFace->num_fixed_sizes - 1;
1533         actualPointSize = ftFace->available_sizes[fixedSizeIndex].size;
1534       }
1535
1536       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize );
1537
1538       // Tell Freetype to use this size
1539       error = FT_Select_Size( ftFace, fixedSizeIndex );
1540       if ( FT_Err_Ok != error )
1541       {
1542         DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Select_Size error: %d\n", error );
1543       }
1544       else
1545       {
1546         float fixedWidth  = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].width );
1547         float fixedHeight = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].height );
1548
1549         // Indicate that the font is a fixed sized bitmap
1550         FontMetrics metrics( fixedHeight, // The ascender in pixels.
1551                              0.0f,
1552                              fixedHeight, // The height in pixels.
1553                              0.0f,
1554                              0.0f );
1555
1556         mFontFaceCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedWidth, fixedHeight, hasColorTables ) );
1557         id = mFontFaceCache.size();
1558       }
1559     }
1560     else
1561     {
1562       error = FT_Set_Char_Size( ftFace,
1563                                 0,
1564                                 requestedPointSize,
1565                                 mDpiHorizontal,
1566                                 mDpiVertical );
1567
1568       if( FT_Err_Ok == error )
1569       {
1570
1571         FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1572
1573         FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
1574                              static_cast< float >( ftMetrics.descender ) * FROM_266,
1575                              static_cast< float >( ftMetrics.height    ) * FROM_266,
1576                              static_cast< float >( ftFace->underline_position ) * FROM_266,
1577                              static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1578
1579         mFontFaceCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics ) );
1580         id = mFontFaceCache.size();
1581       }
1582       else
1583       {
1584         DALI_LOG_INFO( gLogFilter, Debug::General, "  FreeType Set_Char_Size error: %d for pointSize %d\n", error, requestedPointSize );
1585       }
1586     }
1587
1588     if( 0u != id )
1589     {
1590       if( cacheDescription )
1591       {
1592         CacheFontPath( ftFace, id, requestedPointSize, path );
1593       }
1594     }
1595   }
1596   else
1597   {
1598     DALI_LOG_INFO( gLogFilter, Debug::General, "  FreeType New_Face error: %d for [%s]\n", error, path.c_str() );
1599   }
1600
1601   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
1602   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::CreateFont\n" );
1603
1604   return id;
1605 }
1606
1607 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap )
1608 {
1609   if( srcBitmap.width*srcBitmap.rows > 0 )
1610   {
1611     switch( srcBitmap.pixel_mode )
1612     {
1613       case FT_PIXEL_MODE_GRAY:
1614       {
1615         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
1616         {
1617           const unsigned int bufferSize = srcBitmap.width * srcBitmap.rows;
1618           data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1619           data.width = srcBitmap.width;
1620           data.height = srcBitmap.rows;
1621           data.format = Pixel::L8;
1622           memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1623         }
1624         break;
1625       }
1626
1627 #ifdef FREETYPE_BITMAP_SUPPORT
1628       case FT_PIXEL_MODE_BGRA:
1629       {
1630         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
1631         {
1632           // Set the input dimensions.
1633           const ImageDimensions inputDimensions( srcBitmap.width, srcBitmap.rows );
1634
1635           // Set the output dimensions.
1636           // If the output dimension is not given, the input dimension is set
1637           // and won't be downscaling.
1638           data.width = ( data.width == 0 ) ? srcBitmap.width : data.width;
1639           data.height = ( data.height == 0 ) ? srcBitmap.rows : data.height;
1640           const ImageDimensions desiredDimensions( data.width, data.height );
1641
1642           // Creates the output buffer
1643           const unsigned int bufferSize = data.width * data.height * 4u;
1644           data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1645
1646           if( inputDimensions == desiredDimensions )
1647           {
1648             // There isn't downscaling.
1649             memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1650           }
1651           else
1652           {
1653             Dali::Internal::Platform::LanczosSample4BPP( srcBitmap.buffer,
1654                                                          inputDimensions,
1655                                                          data.buffer,
1656                                                          desiredDimensions );
1657           }
1658           data.format = Pixel::BGRA8888;
1659         }
1660         break;
1661       }
1662 #endif
1663       default:
1664       {
1665         DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::ConvertBitmap. FontClient Unable to create Bitmap of this PixelType\n" );
1666         break;
1667       }
1668     }
1669   }
1670 }
1671
1672 bool FontClient::Plugin::FindFont( const FontPath& path,
1673                                    PointSize26Dot6 requestedPointSize,
1674                                    FaceIndex faceIndex,
1675                                    FontId& fontId ) const
1676 {
1677   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
1678   DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
1679   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1680   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of fonts in the cache : %d\n", mFontFaceCache.size() );
1681
1682   fontId = 0u;
1683   for( const auto& cacheItem : mFontFaceCache )
1684   {
1685     ++fontId;
1686     if( cacheItem.mRequestedPointSize == requestedPointSize &&
1687         cacheItem.mFaceIndex == faceIndex &&
1688         cacheItem.mPath == path )
1689     {
1690
1691       DALI_LOG_INFO( gLogFilter, Debug::General, "  font found, id : %d\n", fontId );
1692       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1693
1694       return true;
1695     }
1696   }
1697
1698   DALI_LOG_INFO( gLogFilter, Debug::General, "  font not found\n" );
1699   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1700
1701   fontId = 0u;
1702   return false;
1703 }
1704
1705 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1706                                             FontDescriptionId& validatedFontId )
1707 {
1708   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindValidatedFont\n" );
1709   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1710   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1711   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1712   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1713   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1714   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of validated fonts in the cache : %d\n", mValidatedFontCache.size() );
1715
1716   validatedFontId = 0u;
1717
1718   for( const auto& item : mValidatedFontCache )
1719   {
1720     if( !fontDescription.family.empty() &&
1721         ( fontDescription.family == item.fontDescription.family ) &&
1722         ( fontDescription.width == item.fontDescription.width ) &&
1723         ( fontDescription.weight == item.fontDescription.weight ) &&
1724         ( fontDescription.slant == item.fontDescription.slant ) )
1725     {
1726       validatedFontId = item.index;
1727
1728       DALI_LOG_INFO( gLogFilter, Debug::General, "  validated font found, id : %d\n", validatedFontId );
1729       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
1730       return true;
1731     }
1732   }
1733
1734   DALI_LOG_INFO( gLogFilter, Debug::General, "  validated font not found\n" );
1735   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
1736   return false;
1737 }
1738
1739 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
1740                                                FontList*& fontList,
1741                                                CharacterSetList*& characterSetList )
1742 {
1743   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFontList\n" );
1744   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1745   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1746   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1747   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1748   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1749   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of fallback font lists in the cache : %d\n", mFallbackCache.size() );
1750
1751   fontList = nullptr;
1752
1753   for( const auto& item : mFallbackCache )
1754   {
1755     if( !fontDescription.family.empty() &&
1756         ( fontDescription.family == item.fontDescription.family ) &&
1757         ( fontDescription.width == item.fontDescription.width ) &&
1758         ( fontDescription.weight == item.fontDescription.weight ) &&
1759         ( fontDescription.slant == item.fontDescription.slant ) )
1760     {
1761       fontList = item.fallbackFonts;
1762       characterSetList = item.characterSets;
1763
1764       DALI_LOG_INFO( gLogFilter, Debug::General, "  fallback font list found.\n" );
1765       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
1766       return true;
1767     }
1768   }
1769
1770   DALI_LOG_INFO( gLogFilter, Debug::General, "  fallback font list not found.\n" );
1771   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
1772   return false;
1773 }
1774
1775 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1776                                    PointSize26Dot6 requestedPointSize,
1777                                    FontId& fontId )
1778 {
1779   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
1780   DALI_LOG_INFO( gLogFilter, Debug::General, "    validatedFontId  : %d\n", validatedFontId );
1781   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1782
1783   fontId = 0u;
1784
1785   for( const auto& item : mFontDescriptionSizeCache )
1786   {
1787     if( ( validatedFontId == item.validatedFontId ) &&
1788         ( requestedPointSize == item.requestedPointSize ) )
1789     {
1790       fontId = item.fontId;
1791
1792       DALI_LOG_INFO( gLogFilter, Debug::General, "  font found, id : %d\n", fontId );
1793       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1794       return true;
1795     }
1796   }
1797
1798   DALI_LOG_INFO( gLogFilter, Debug::General, "  font not found.\n" );
1799   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1800   return false;
1801 }
1802
1803 bool FontClient::Plugin::IsScalable( const FontPath& path )
1804 {
1805   bool isScalable = false;
1806
1807   FT_Face ftFace;
1808   int error = FT_New_Face( mFreeTypeLibrary,
1809                            path.c_str(),
1810                            0,
1811                            &ftFace );
1812   if( FT_Err_Ok != error )
1813   {
1814     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: %s\n", path.c_str() );
1815   }
1816   else
1817   {
1818     isScalable = ftFace->face_flags & FT_FACE_FLAG_SCALABLE;
1819   }
1820
1821   return isScalable;
1822 }
1823
1824 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1825 {
1826   // Create a font pattern.
1827   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1828
1829   FcResult result = FcResultMatch;
1830
1831   // match the pattern
1832   FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result );
1833   bool isScalable = false;
1834
1835   if( match )
1836   {
1837     // Get the path to the font file name.
1838     FontPath path;
1839     GetFcString( match, FC_FILE, path );
1840     isScalable = IsScalable( path );
1841   }
1842   else
1843   {
1844     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
1845   }
1846   FcPatternDestroy( fontFamilyPattern );
1847   FcPatternDestroy( match );
1848   return isScalable;
1849 }
1850
1851 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1852 {
1853   // Empty the caller container
1854   sizes.Clear();
1855
1856   FT_Face ftFace;
1857   int error = FT_New_Face( mFreeTypeLibrary,
1858                            path.c_str(),
1859                            0,
1860                            &ftFace );
1861   if( FT_Err_Ok != error )
1862   {
1863     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font path : [%s]\n", path.c_str() );
1864   }
1865
1866   // Fetch the number of fixed sizes available
1867   if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1868   {
1869     for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1870     {
1871       sizes.PushBack( ftFace->available_sizes[ i ].size );
1872     }
1873   }
1874 }
1875
1876 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1877                                         Vector< PointSize26Dot6 >& sizes )
1878 {
1879   // Create a font pattern.
1880   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1881
1882   FcResult result = FcResultMatch;
1883
1884   // match the pattern
1885   FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result );
1886
1887   if( match )
1888   {
1889     // Get the path to the font file name.
1890     FontPath path;
1891     GetFcString( match, FC_FILE, path );
1892     GetFixedSizes( path, sizes );
1893   }
1894   else
1895   {
1896     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
1897   }
1898   FcPatternDestroy( match );
1899   FcPatternDestroy( fontFamilyPattern );
1900 }
1901
1902 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize,  const FontPath& path )
1903 {
1904   FontDescription description;
1905   description.path = path;
1906   description.family = std::move( FontFamily( ftFace->family_name ) );
1907   description.weight = FontWeight::NONE;
1908   description.width = FontWidth::NONE;
1909   description.slant = FontSlant::NONE;
1910
1911   // Note FreeType doesn't give too much info to build a proper font style.
1912   if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1913   {
1914     description.slant = FontSlant::ITALIC;
1915   }
1916   if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1917   {
1918     description.weight = FontWeight::BOLD;
1919   }
1920
1921   FontDescriptionId validatedFontId = 0u;
1922   if( !FindValidatedFont( description,
1923                           validatedFontId ) )
1924   {
1925     // Set the index to the vector of paths to font file names.
1926     validatedFontId = mFontDescriptionCache.size();
1927
1928     FcPattern* pattern = CreateFontFamilyPattern( description );
1929
1930     FcResult result = FcResultMatch;
1931     FcPattern* match = FcFontMatch( nullptr, pattern, &result );
1932
1933     FcCharSet* characterSet = nullptr;
1934     FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
1935
1936     FcPatternDestroy( pattern );
1937
1938     mMatchedFcPatternCache.PushBack( match );
1939
1940     mFontFaceCache[id-1u].mCharacterSet = characterSet;
1941
1942     // Add the path to the cache.
1943     mFontDescriptionCache.push_back( description );
1944     mCharacterSetCache.PushBack( characterSet );
1945
1946     // Cache the index and the font's description.
1947     mValidatedFontCache.push_back( std::move( FontDescriptionCacheItem( std::move( description ),
1948                                                                         validatedFontId) ) );
1949
1950     // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
1951     mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId,
1952                                                                        requestedPointSize,
1953                                                                        id ) );
1954   }
1955 }
1956
1957 FcCharSet* FontClient::Plugin::CreateCharacterSetFromDescription( const FontDescription& description )
1958 {
1959   FcCharSet* characterSet = nullptr;
1960
1961   FcPattern* pattern = CreateFontFamilyPattern( description );
1962
1963   if( nullptr != pattern )
1964   {
1965     FcResult result = FcResultMatch;
1966     FcPattern* match = FcFontMatch( nullptr, pattern, &result );
1967
1968     FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
1969     mMatchedFcPatternCache.PushBack( match );
1970
1971     FcPatternDestroy( pattern );
1972   }
1973
1974   return characterSet;
1975 }
1976
1977 void FontClient::Plugin::DestroyMatchedPatterns()
1978 {
1979   for (auto & object : mMatchedFcPatternCache)
1980   {
1981     FcPatternDestroy(reinterpret_cast<FcPattern*>(object));
1982   }
1983   mMatchedFcPatternCache.Clear();
1984 }
1985
1986 } // namespace Internal
1987
1988 } // namespace TextAbstraction
1989
1990 } // namespace Dali