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