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