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