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