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