Add locale property setting
[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 FT_FaceRec_* FontClient::Plugin::GetFreetypeFace( FontId fontId )
1274 {
1275   FT_Face fontFace = nullptr;
1276
1277   if( ( fontId > 0u ) &&
1278       ( fontId - 1u < mFontFaceCache.size() ) )
1279   {
1280     fontFace = mFontFaceCache[fontId - 1u].mFreeTypeFace;
1281   }
1282
1283   return fontFace;
1284 }
1285
1286 void FontClient::Plugin::InitSystemFonts()
1287 {
1288   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::InitSystemFonts\n" );
1289
1290   FcFontSet* fontSet = GetFcFontSet();
1291
1292   if( fontSet )
1293   {
1294     DALI_LOG_INFO( gLogFilter, Debug::General, "  number of system fonts : %d\n", fontSet->nfont );
1295
1296     // Reserve some space to avoid reallocations.
1297     mSystemFonts.reserve( fontSet->nfont );
1298
1299     for( int i = 0u; i < fontSet->nfont; ++i )
1300     {
1301       FcPattern* fontPattern = fontSet->fonts[i];
1302
1303       FontPath path;
1304
1305       // Skip fonts with no path
1306       if( GetFcString( fontPattern, FC_FILE, path ) )
1307       {
1308         mSystemFonts.push_back( FontDescription() );
1309         FontDescription& fontDescription = mSystemFonts.back();
1310
1311         fontDescription.path = std::move( path );
1312
1313         int width = 0;
1314         int weight = 0;
1315         int slant = 0;
1316         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
1317         GetFcInt( fontPattern, FC_WIDTH, width );
1318         GetFcInt( fontPattern, FC_WEIGHT, weight );
1319         GetFcInt( fontPattern, FC_SLANT, slant );
1320         fontDescription.width = IntToWidthType( width );
1321         fontDescription.weight = IntToWeightType( weight );
1322         fontDescription.slant = IntToSlantType( slant );
1323
1324         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  description; family : [%s]\n", fontDescription.family.c_str() );
1325         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1326         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1327         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1328         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1329       }
1330     }
1331
1332     FcFontSetDestroy( fontSet );
1333   }
1334   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::InitSystemFonts\n" );
1335 }
1336
1337 bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet )
1338 {
1339   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1340
1341   FcResult result = FcResultMatch;
1342   FcPattern* match = FcFontMatch( nullptr /* use default configure */, pattern, &result );
1343
1344   const bool matched = nullptr != match;
1345   DALI_LOG_INFO( gLogFilter, Debug::General, "  pattern matched : %s\n", ( matched ? "true" : "false" ) );
1346
1347   if( matched )
1348   {
1349     int width = 0;
1350     int weight = 0;
1351     int slant = 0;
1352     GetFcString( match, FC_FILE, fontDescription.path );
1353     GetFcString( match, FC_FAMILY, fontDescription.family );
1354     GetFcInt( match, FC_WIDTH, width );
1355     GetFcInt( match, FC_WEIGHT, weight );
1356     GetFcInt( match, FC_SLANT, slant );
1357     fontDescription.width = IntToWidthType( width );
1358     fontDescription.weight = IntToWeightType( weight );
1359     fontDescription.slant = IntToSlantType( slant );
1360
1361     // Cache the character ranges.
1362     FcPatternGetCharSet( match, FC_CHARSET, 0u, characterSet );
1363
1364     // destroyed the matched pattern
1365     FcPatternDestroy( match );
1366
1367     DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1368     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1369     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1370     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1371     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1372   }
1373
1374   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1375   return matched;
1376 }
1377
1378 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription ) const
1379 {
1380   // create the cached font family lookup pattern
1381   // a pattern holds a set of names, each name refers to a property of the font
1382   FcPattern* fontFamilyPattern = FcPatternCreate();
1383
1384   if( !fontFamilyPattern )
1385   {
1386     return nullptr;
1387   }
1388
1389   // add a property to the pattern for the font family
1390   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
1391
1392   // add a property to the pattern for local setting.
1393   const char* locale = setlocale( LC_MESSAGES, NULL );
1394   if( locale != NULL)
1395   {
1396     FcPatternAddString( fontFamilyPattern, FC_LANG, reinterpret_cast<const FcChar8*>( locale ) );
1397   }
1398
1399   int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
1400   if( width < 0 )
1401   {
1402     // Use default.
1403     width = DEFAULT_FONT_WIDTH;
1404   }
1405
1406   int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
1407   if( weight < 0 )
1408   {
1409     // Use default.
1410     weight = DEFAULT_FONT_WEIGHT;
1411   }
1412
1413   int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
1414   if( slant < 0 )
1415   {
1416     // Use default.
1417     slant = DEFAULT_FONT_SLANT;
1418   }
1419
1420   FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
1421   FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
1422   FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
1423
1424   // Add a property of the pattern, to say we want to match TrueType fonts
1425   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
1426
1427   // modify the config, with the mFontFamilyPatterm
1428   FcConfigSubstitute( nullptr /* use default configure */, fontFamilyPattern, FcMatchPattern );
1429
1430   // provide default values for unspecified properties in the font pattern
1431   // e.g. patterns without a specified style or weight are set to Medium
1432   FcDefaultSubstitute( fontFamilyPattern );
1433
1434   return fontFamilyPattern;
1435 }
1436
1437 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
1438 {
1439   // create a new pattern.
1440   // a pattern holds a set of names, each name refers to a property of the font
1441   FcPattern* pattern = FcPatternCreate();
1442
1443   FcFontSet* fontset = NULL;
1444
1445   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
1446   FcObjectSet* objectSet = FcObjectSetCreate();
1447
1448   if( objectSet )
1449   {
1450     // build an object set from a list of property names
1451     FcObjectSetAdd( objectSet, FC_FILE );
1452     FcObjectSetAdd( objectSet, FC_FAMILY );
1453     FcObjectSetAdd( objectSet, FC_WIDTH );
1454     FcObjectSetAdd( objectSet, FC_WEIGHT );
1455     FcObjectSetAdd( objectSet, FC_SLANT );
1456
1457     // get a list of fonts
1458     // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
1459     fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
1460
1461     // clear up the object set
1462     FcObjectSetDestroy( objectSet );
1463   }
1464   // clear up the pattern
1465   if( pattern )
1466   {
1467     FcPatternDestroy( pattern );
1468   }
1469
1470   return fontset;
1471 }
1472
1473 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1474                                       const char* const n,
1475                                       std::string& string )
1476 {
1477   FcChar8* file = nullptr;
1478   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1479
1480   if( FcResultMatch == retVal )
1481   {
1482     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1483     string.assign( reinterpret_cast<const char*>( file ) );
1484
1485     return true;
1486   }
1487
1488   return false;
1489 }
1490
1491 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
1492 {
1493   const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
1494
1495   if( FcResultMatch == retVal )
1496   {
1497     return true;
1498   }
1499
1500   return false;
1501 }
1502
1503 FontId FontClient::Plugin::CreateFont( const FontPath& path,
1504                                        PointSize26Dot6 requestedPointSize,
1505                                        FaceIndex faceIndex,
1506                                        bool cacheDescription )
1507 {
1508   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::CreateFont\n" );
1509   DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
1510   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1511
1512   FontId id = 0u;
1513
1514   // Create & cache new font face
1515   FT_Face ftFace;
1516   int error = FT_New_Face( mFreeTypeLibrary,
1517                            path.c_str(),
1518                            0,
1519                            &ftFace );
1520
1521   if( FT_Err_Ok == error )
1522   {
1523     // Check if a font is scalable.
1524     const bool isScalable = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_SCALABLE ) );
1525     const bool hasFixedSizedBitmaps = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_FIXED_SIZES ) ) && ( 0 != ftFace->num_fixed_sizes );
1526     const bool hasColorTables = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_COLOR ) );
1527
1528     DALI_LOG_INFO( gLogFilter, Debug::General, "            isScalable : [%s]\n", ( isScalable ? "true" : "false" ) );
1529     DALI_LOG_INFO( gLogFilter, Debug::General, "  hasFixedSizedBitmaps : [%s]\n", ( hasFixedSizedBitmaps ? "true" : "false" ) );
1530     DALI_LOG_INFO( gLogFilter, Debug::General, "        hasColorTables : [%s]\n", ( hasColorTables ? "true" : "false" ) );
1531
1532     // Check to see if the font contains fixed sizes?
1533     if( !isScalable && hasFixedSizedBitmaps )
1534     {
1535       PointSize26Dot6 actualPointSize = 0u;
1536       int fixedSizeIndex = 0;
1537       for( ; fixedSizeIndex < ftFace->num_fixed_sizes; ++fixedSizeIndex )
1538       {
1539         const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size;
1540         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  size index : %d, size : %d\n", fixedSizeIndex, fixedSize );
1541
1542         if( fixedSize >= requestedPointSize )
1543         {
1544           actualPointSize = fixedSize;
1545           break;
1546         }
1547       }
1548
1549       if( 0u == actualPointSize )
1550       {
1551         // The requested point size is bigger than the bigest fixed size.
1552         fixedSizeIndex = ftFace->num_fixed_sizes - 1;
1553         actualPointSize = ftFace->available_sizes[fixedSizeIndex].size;
1554       }
1555
1556       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize );
1557
1558       // Tell Freetype to use this size
1559       error = FT_Select_Size( ftFace, fixedSizeIndex );
1560       if ( FT_Err_Ok != error )
1561       {
1562         DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Select_Size error: %d\n", error );
1563       }
1564       else
1565       {
1566         float fixedWidth  = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].width );
1567         float fixedHeight = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].height );
1568
1569         // Indicate that the font is a fixed sized bitmap
1570         FontMetrics metrics( fixedHeight, // The ascender in pixels.
1571                              0.0f,
1572                              fixedHeight, // The height in pixels.
1573                              0.0f,
1574                              0.0f );
1575
1576         mFontFaceCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedWidth, fixedHeight, hasColorTables ) );
1577         id = mFontFaceCache.size();
1578       }
1579     }
1580     else
1581     {
1582       error = FT_Set_Char_Size( ftFace,
1583                                 0,
1584                                 requestedPointSize,
1585                                 mDpiHorizontal,
1586                                 mDpiVertical );
1587
1588       if( FT_Err_Ok == error )
1589       {
1590
1591         FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1592
1593         FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
1594                              static_cast< float >( ftMetrics.descender ) * FROM_266,
1595                              static_cast< float >( ftMetrics.height    ) * FROM_266,
1596                              static_cast< float >( ftFace->underline_position ) * FROM_266,
1597                              static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1598
1599         mFontFaceCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics ) );
1600         id = mFontFaceCache.size();
1601       }
1602       else
1603       {
1604         DALI_LOG_INFO( gLogFilter, Debug::General, "  FreeType Set_Char_Size error: %d for pointSize %d\n", error, requestedPointSize );
1605       }
1606     }
1607
1608     if( 0u != id )
1609     {
1610       if( cacheDescription )
1611       {
1612         CacheFontPath( ftFace, id, requestedPointSize, path );
1613       }
1614     }
1615   }
1616   else
1617   {
1618     DALI_LOG_INFO( gLogFilter, Debug::General, "  FreeType New_Face error: %d for [%s]\n", error, path.c_str() );
1619   }
1620
1621   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
1622   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::CreateFont\n" );
1623
1624   return id;
1625 }
1626
1627 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap )
1628 {
1629   if( srcBitmap.width*srcBitmap.rows > 0 )
1630   {
1631     switch( srcBitmap.pixel_mode )
1632     {
1633       case FT_PIXEL_MODE_GRAY:
1634       {
1635         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
1636         {
1637           const unsigned int bufferSize = srcBitmap.width * srcBitmap.rows;
1638           data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1639           data.width = srcBitmap.width;
1640           data.height = srcBitmap.rows;
1641           data.format = Pixel::L8;
1642           memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1643         }
1644         break;
1645       }
1646
1647 #ifdef FREETYPE_BITMAP_SUPPORT
1648       case FT_PIXEL_MODE_BGRA:
1649       {
1650         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
1651         {
1652           // Set the input dimensions.
1653           const ImageDimensions inputDimensions( srcBitmap.width, srcBitmap.rows );
1654
1655           // Set the output dimensions.
1656           // If the output dimension is not given, the input dimension is set
1657           // and won't be downscaling.
1658           data.width = ( data.width == 0 ) ? srcBitmap.width : data.width;
1659           data.height = ( data.height == 0 ) ? srcBitmap.rows : data.height;
1660           const ImageDimensions desiredDimensions( data.width, data.height );
1661
1662           // Creates the output buffer
1663           const unsigned int bufferSize = data.width * data.height * 4u;
1664           data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1665
1666           if( inputDimensions == desiredDimensions )
1667           {
1668             // There isn't downscaling.
1669             memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1670           }
1671           else
1672           {
1673             Dali::Internal::Platform::LanczosSample4BPP( srcBitmap.buffer,
1674                                                          inputDimensions,
1675                                                          data.buffer,
1676                                                          desiredDimensions );
1677           }
1678           data.format = Pixel::BGRA8888;
1679         }
1680         break;
1681       }
1682 #endif
1683       default:
1684       {
1685         DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::ConvertBitmap. FontClient Unable to create Bitmap of this PixelType\n" );
1686         break;
1687       }
1688     }
1689   }
1690 }
1691
1692 bool FontClient::Plugin::FindFont( const FontPath& path,
1693                                    PointSize26Dot6 requestedPointSize,
1694                                    FaceIndex faceIndex,
1695                                    FontId& fontId ) const
1696 {
1697   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
1698   DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
1699   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1700   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of fonts in the cache : %d\n", mFontFaceCache.size() );
1701
1702   fontId = 0u;
1703   for( const auto& cacheItem : mFontFaceCache )
1704   {
1705     ++fontId;
1706     if( cacheItem.mRequestedPointSize == requestedPointSize &&
1707         cacheItem.mFaceIndex == faceIndex &&
1708         cacheItem.mPath == path )
1709     {
1710
1711       DALI_LOG_INFO( gLogFilter, Debug::General, "  font found, id : %d\n", fontId );
1712       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1713
1714       return true;
1715     }
1716   }
1717
1718   DALI_LOG_INFO( gLogFilter, Debug::General, "  font not found\n" );
1719   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1720
1721   fontId = 0u;
1722   return false;
1723 }
1724
1725 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1726                                             FontDescriptionId& validatedFontId )
1727 {
1728   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindValidatedFont\n" );
1729   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1730   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1731   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1732   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1733   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1734   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of validated fonts in the cache : %d\n", mValidatedFontCache.size() );
1735
1736   validatedFontId = 0u;
1737
1738   for( const auto& item : mValidatedFontCache )
1739   {
1740     if( !fontDescription.family.empty() &&
1741         ( fontDescription.family == item.fontDescription.family ) &&
1742         ( fontDescription.width == item.fontDescription.width ) &&
1743         ( fontDescription.weight == item.fontDescription.weight ) &&
1744         ( fontDescription.slant == item.fontDescription.slant ) )
1745     {
1746       validatedFontId = item.index;
1747
1748       DALI_LOG_INFO( gLogFilter, Debug::General, "  validated font found, id : %d\n", validatedFontId );
1749       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
1750       return true;
1751     }
1752   }
1753
1754   DALI_LOG_INFO( gLogFilter, Debug::General, "  validated font not found\n" );
1755   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
1756   return false;
1757 }
1758
1759 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
1760                                                FontList*& fontList,
1761                                                CharacterSetList*& characterSetList )
1762 {
1763   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFontList\n" );
1764   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1765   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1766   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1767   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1768   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1769   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of fallback font lists in the cache : %d\n", mFallbackCache.size() );
1770
1771   fontList = nullptr;
1772
1773   for( const auto& item : mFallbackCache )
1774   {
1775     if( !fontDescription.family.empty() &&
1776         ( fontDescription.family == item.fontDescription.family ) &&
1777         ( fontDescription.width == item.fontDescription.width ) &&
1778         ( fontDescription.weight == item.fontDescription.weight ) &&
1779         ( fontDescription.slant == item.fontDescription.slant ) )
1780     {
1781       fontList = item.fallbackFonts;
1782       characterSetList = item.characterSets;
1783
1784       DALI_LOG_INFO( gLogFilter, Debug::General, "  fallback font list found.\n" );
1785       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
1786       return true;
1787     }
1788   }
1789
1790   DALI_LOG_INFO( gLogFilter, Debug::General, "  fallback font list not found.\n" );
1791   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
1792   return false;
1793 }
1794
1795 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1796                                    PointSize26Dot6 requestedPointSize,
1797                                    FontId& fontId )
1798 {
1799   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
1800   DALI_LOG_INFO( gLogFilter, Debug::General, "    validatedFontId  : %d\n", validatedFontId );
1801   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1802
1803   fontId = 0u;
1804
1805   for( const auto& item : mFontDescriptionSizeCache )
1806   {
1807     if( ( validatedFontId == item.validatedFontId ) &&
1808         ( requestedPointSize == item.requestedPointSize ) )
1809     {
1810       fontId = item.fontId;
1811
1812       DALI_LOG_INFO( gLogFilter, Debug::General, "  font found, id : %d\n", fontId );
1813       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1814       return true;
1815     }
1816   }
1817
1818   DALI_LOG_INFO( gLogFilter, Debug::General, "  font not found.\n" );
1819   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1820   return false;
1821 }
1822
1823 bool FontClient::Plugin::IsScalable( const FontPath& path )
1824 {
1825   bool isScalable = false;
1826
1827   FT_Face ftFace;
1828   int error = FT_New_Face( mFreeTypeLibrary,
1829                            path.c_str(),
1830                            0,
1831                            &ftFace );
1832   if( FT_Err_Ok != error )
1833   {
1834     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: %s\n", path.c_str() );
1835   }
1836   else
1837   {
1838     isScalable = ftFace->face_flags & FT_FACE_FLAG_SCALABLE;
1839   }
1840
1841   return isScalable;
1842 }
1843
1844 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1845 {
1846   // Create a font pattern.
1847   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1848
1849   FcResult result = FcResultMatch;
1850
1851   // match the pattern
1852   FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result );
1853   bool isScalable = false;
1854
1855   if( match )
1856   {
1857     // Get the path to the font file name.
1858     FontPath path;
1859     GetFcString( match, FC_FILE, path );
1860     isScalable = IsScalable( path );
1861   }
1862   else
1863   {
1864     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
1865   }
1866   FcPatternDestroy( fontFamilyPattern );
1867   FcPatternDestroy( match );
1868   return isScalable;
1869 }
1870
1871 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1872 {
1873   // Empty the caller container
1874   sizes.Clear();
1875
1876   FT_Face ftFace;
1877   int error = FT_New_Face( mFreeTypeLibrary,
1878                            path.c_str(),
1879                            0,
1880                            &ftFace );
1881   if( FT_Err_Ok != error )
1882   {
1883     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font path : [%s]\n", path.c_str() );
1884   }
1885
1886   // Fetch the number of fixed sizes available
1887   if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1888   {
1889     for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1890     {
1891       sizes.PushBack( ftFace->available_sizes[ i ].size );
1892     }
1893   }
1894 }
1895
1896 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1897                                         Vector< PointSize26Dot6 >& sizes )
1898 {
1899   // Create a font pattern.
1900   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1901
1902   FcResult result = FcResultMatch;
1903
1904   // match the pattern
1905   FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result );
1906
1907   if( match )
1908   {
1909     // Get the path to the font file name.
1910     FontPath path;
1911     GetFcString( match, FC_FILE, path );
1912     GetFixedSizes( path, sizes );
1913   }
1914   else
1915   {
1916     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
1917   }
1918   FcPatternDestroy( match );
1919   FcPatternDestroy( fontFamilyPattern );
1920 }
1921
1922 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize,  const FontPath& path )
1923 {
1924   FontDescription description;
1925   description.path = path;
1926   description.family = std::move( FontFamily( ftFace->family_name ) );
1927   description.weight = FontWeight::NONE;
1928   description.width = FontWidth::NONE;
1929   description.slant = FontSlant::NONE;
1930
1931   // Note FreeType doesn't give too much info to build a proper font style.
1932   if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1933   {
1934     description.slant = FontSlant::ITALIC;
1935   }
1936   if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1937   {
1938     description.weight = FontWeight::BOLD;
1939   }
1940
1941   FontDescriptionId validatedFontId = 0u;
1942   if( !FindValidatedFont( description,
1943                           validatedFontId ) )
1944   {
1945     // Set the index to the vector of paths to font file names.
1946     validatedFontId = mFontDescriptionCache.size();
1947
1948     FcPattern* pattern = CreateFontFamilyPattern( description );
1949
1950     FcResult result = FcResultMatch;
1951     FcPattern* match = FcFontMatch( nullptr, pattern, &result );
1952
1953     FcCharSet* characterSet = nullptr;
1954     FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
1955
1956     FcPatternDestroy( pattern );
1957
1958     mMatchedFcPatternCache.PushBack( match );
1959
1960     mFontFaceCache[id-1u].mCharacterSet = characterSet;
1961
1962     // Add the path to the cache.
1963     mFontDescriptionCache.push_back( description );
1964     mCharacterSetCache.PushBack( characterSet );
1965
1966     // Cache the index and the font's description.
1967     mValidatedFontCache.push_back( std::move( FontDescriptionCacheItem( std::move( description ),
1968                                                                         validatedFontId) ) );
1969
1970     // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
1971     mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId,
1972                                                                        requestedPointSize,
1973                                                                        id ) );
1974   }
1975 }
1976
1977 FcCharSet* FontClient::Plugin::CreateCharacterSetFromDescription( const FontDescription& description )
1978 {
1979   FcCharSet* characterSet = nullptr;
1980
1981   FcPattern* pattern = CreateFontFamilyPattern( description );
1982
1983   if( nullptr != pattern )
1984   {
1985     FcResult result = FcResultMatch;
1986     FcPattern* match = FcFontMatch( nullptr, pattern, &result );
1987
1988     FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
1989     mMatchedFcPatternCache.PushBack( match );
1990
1991     FcPatternDestroy( pattern );
1992   }
1993
1994   return characterSet;
1995 }
1996
1997 void FontClient::Plugin::DestroyMatchedPatterns()
1998 {
1999   for (auto & object : mMatchedFcPatternCache)
2000   {
2001     FcPatternDestroy(reinterpret_cast<FcPattern*>(object));
2002   }
2003   mMatchedFcPatternCache.Clear();
2004 }
2005
2006 } // namespace Internal
2007
2008 } // namespace TextAbstraction
2009
2010 } // namespace Dali