Revert "[Tizen] Support custom fonts registration"
[platform/core/uifw/dali-adaptor.git] / dali / internal / text / 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/text-abstraction/font-client-plugin-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/devel-api/text-abstraction/font-list.h>
23 #include <dali/public-api/common/dali-vector.h>
24 #include <dali/public-api/common/vector-wrapper.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/integration-api/platform-abstraction.h>
27 #include <dali/internal/text/text-abstraction/font-client-helper.h>
28 #include <dali/internal/imaging/common/image-operations.h>
29 #include <dali/internal/adaptor/common/adaptor-impl.h>
30
31 // EXTERNAL INCLUDES
32 #include <fontconfig/fontconfig.h>
33
34 namespace
35 {
36
37 #if defined(DEBUG_ENABLED)
38 Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
39 #endif
40
41 /**
42  * Conversion from Fractional26.6 to float
43  */
44 const float FROM_266 = 1.0f / 64.0f;
45 const float POINTS_PER_INCH = 72.f;
46
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_NO_AUTOHINT );
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, int outlineWidth )
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_NO_AUTOHINT );
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           // Check whether we should create a bitmap for the outline
1118           if( glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0 )
1119           {
1120             // Set up a stroker
1121             FT_Stroker stroker;
1122             error = FT_Stroker_New(mFreeTypeLibrary, &stroker );
1123
1124             if ( FT_Err_Ok == error )
1125             {
1126               FT_Stroker_Set( stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0 );
1127               error = FT_Glyph_StrokeBorder( &glyph, stroker, 0, 1 );
1128
1129               if ( FT_Err_Ok == error )
1130               {
1131                 FT_Stroker_Done( stroker );
1132               }
1133               else
1134               {
1135                 DALI_LOG_ERROR( "FT_Glyph_StrokeBorder Failed with error: %d\n", error );
1136               }
1137             }
1138             else
1139             {
1140               DALI_LOG_ERROR( "FT_Stroker_New Failed with error: %d\n", error );
1141             }
1142           }
1143
1144           error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
1145           if ( FT_Err_Ok == error )
1146           {
1147             FT_BitmapGlyph bitmapGlyph = reinterpret_cast< FT_BitmapGlyph >( glyph );
1148             ConvertBitmap( data, bitmapGlyph->bitmap );
1149           }
1150           else
1151           {
1152             DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Get_Glyph Failed with error: %d\n", error );
1153           }
1154         }
1155         else
1156         {
1157           ConvertBitmap( data, ftFace->glyph->bitmap );
1158         }
1159
1160         // Created FT_Glyph object must be released with FT_Done_Glyph
1161         FT_Done_Glyph( glyph );
1162       }
1163     }
1164     else
1165     {
1166       DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Load_Glyph Failed with error: %d\n", error );
1167     }
1168   }
1169 }
1170
1171 PixelData FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
1172 {
1173   TextAbstraction::FontClient::GlyphBufferData data;
1174
1175   CreateBitmap( fontId, glyphIndex, data, outlineWidth );
1176
1177   return PixelData::New( data.buffer,
1178                          data.width * data.height * Pixel::GetBytesPerPixel( data.format ),
1179                          data.width,
1180                          data.height,
1181                          data.format,
1182                          PixelData::DELETE_ARRAY );
1183 }
1184
1185 void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
1186 {
1187   blob = NULL;
1188   blobLength = 0;
1189
1190 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
1191   if( fontId > 0 &&
1192       fontId-1 < mFontCache.size() )
1193   {
1194     FontFaceCacheItem& font = mFontCache[fontId-1];
1195
1196     if( ! font.mVectorFontId )
1197     {
1198       font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
1199     }
1200
1201     mVectorFontCache->GetVectorBlob( font.mVectorFontId, fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
1202   }
1203 #endif
1204 }
1205
1206 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize )
1207 {
1208   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetEllipsisGlyph\n" );
1209   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize %d.\n", requestedPointSize );
1210
1211   // First look into the cache if there is an ellipsis glyph for the requested point size.
1212   for( Vector<EllipsisItem>::ConstIterator it = mEllipsisCache.Begin(),
1213          endIt = mEllipsisCache.End();
1214        it != endIt;
1215        ++it )
1216   {
1217     const EllipsisItem& item = *it;
1218
1219     if( fabsf( item.requestedPointSize - requestedPointSize ) < Math::MACHINE_EPSILON_1000 )
1220     {
1221       // Use the glyph in the cache.
1222
1223       DALI_LOG_INFO( gLogFilter, Debug::General, "  glyph id %d found in the cache.\n", item.glyph.index );
1224       DALI_LOG_INFO( gLogFilter, Debug::General, "      font %d.\n", item.glyph.fontId );
1225       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
1226
1227       return item.glyph;
1228     }
1229   }
1230
1231   // No glyph has been found. Create one.
1232   mEllipsisCache.PushBack( EllipsisItem() );
1233   EllipsisItem& item = *( mEllipsisCache.End() - 1u );
1234
1235   item.requestedPointSize = requestedPointSize;
1236
1237   // Find a font for the ellipsis glyph.
1238   item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
1239                                        requestedPointSize,
1240                                        false );
1241
1242   // Set the character index to access the glyph inside the font.
1243   item.glyph.index = FT_Get_Char_Index( mFontCache[item.glyph.fontId-1].mFreeTypeFace,
1244                                         ELLIPSIS_CHARACTER );
1245
1246   GetBitmapMetrics( &item.glyph, 1u, true );
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 bool FontClient::Plugin::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
1256 {
1257   FT_Error error = -1;
1258
1259 #ifdef FREETYPE_BITMAP_SUPPORT
1260   if( ( fontId > 0 ) &&
1261       ( fontId - 1u < mFontCache.size() ) )
1262   {
1263     const FontFaceCacheItem& item = mFontCache[fontId - 1u];
1264     FT_Face ftFace = item.mFreeTypeFace;
1265
1266     // Check to see if this is fixed size bitmap
1267     if( item.mHasColorTables )
1268     {
1269       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1270     }
1271   }
1272 #endif
1273
1274   return FT_Err_Ok == error;
1275 }
1276
1277 void FontClient::Plugin::InitSystemFonts()
1278 {
1279   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::InitSystemFonts\n" );
1280
1281   FcFontSet* fontSet = GetFcFontSet();
1282
1283   if( fontSet )
1284   {
1285     DALI_LOG_INFO( gLogFilter, Debug::General, "  number of system fonts : %d\n", fontSet->nfont );
1286
1287     // Reserve some space to avoid reallocations.
1288     mSystemFonts.reserve( fontSet->nfont );
1289
1290     for( int i = 0u; i < fontSet->nfont; ++i )
1291     {
1292       FcPattern* fontPattern = fontSet->fonts[i];
1293
1294       FontPath path;
1295
1296       // Skip fonts with no path
1297       if( GetFcString( fontPattern, FC_FILE, path ) )
1298       {
1299         mSystemFonts.push_back( FontDescription() );
1300         FontDescription& fontDescription = mSystemFonts.back();
1301
1302         fontDescription.path = path;
1303
1304         int width = 0;
1305         int weight = 0;
1306         int slant = 0;
1307         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
1308         GetFcInt( fontPattern, FC_WIDTH, width );
1309         GetFcInt( fontPattern, FC_WEIGHT, weight );
1310         GetFcInt( fontPattern, FC_SLANT, slant );
1311         fontDescription.width = IntToWidthType( width );
1312         fontDescription.weight = IntToWeightType( weight );
1313         fontDescription.slant = IntToSlantType( slant );
1314
1315         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  description; family : [%s]\n", fontDescription.family.c_str() );
1316         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1317         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1318         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1319         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1320       }
1321     }
1322
1323     FcFontSetDestroy( fontSet );
1324   }
1325   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::InitSystemFonts\n" );
1326 }
1327
1328 bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet )
1329 {
1330   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1331
1332   FcResult result = FcResultMatch;
1333   FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
1334
1335   const bool matched = NULL != match;
1336   DALI_LOG_INFO( gLogFilter, Debug::General, "  pattern matched : %s\n", ( matched ? "true" : "false" ) );
1337
1338   if( matched )
1339   {
1340     int width = 0;
1341     int weight = 0;
1342     int slant = 0;
1343     GetFcString( match, FC_FILE, fontDescription.path );
1344     GetFcString( match, FC_FAMILY, fontDescription.family );
1345     GetFcInt( match, FC_WIDTH, width );
1346     GetFcInt( match, FC_WEIGHT, weight );
1347     GetFcInt( match, FC_SLANT, slant );
1348     fontDescription.width = IntToWidthType( width );
1349     fontDescription.weight = IntToWeightType( weight );
1350     fontDescription.slant = IntToSlantType( slant );
1351
1352     // Cache the character ranges.
1353     FcPatternGetCharSet( match, FC_CHARSET, 0u, characterSet );
1354
1355     // destroyed the matched pattern
1356     FcPatternDestroy( match );
1357
1358     DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1359     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1360     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1361     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1362     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1363   }
1364
1365   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1366   return matched;
1367 }
1368
1369 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription ) const
1370 {
1371   // create the cached font family lookup pattern
1372   // a pattern holds a set of names, each name refers to a property of the font
1373   FcPattern* fontFamilyPattern = FcPatternCreate();
1374
1375   if( !fontFamilyPattern )
1376   {
1377     return NULL;
1378   }
1379
1380   // add a property to the pattern for the font family
1381   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
1382
1383   int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
1384   if( width < 0 )
1385   {
1386     // Use default.
1387     width = DEFAULT_FONT_WIDTH;
1388   }
1389
1390   int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
1391   if( weight < 0 )
1392   {
1393     // Use default.
1394     weight = DEFAULT_FONT_WEIGHT;
1395   }
1396
1397   int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
1398   if( slant < 0 )
1399   {
1400     // Use default.
1401     slant = DEFAULT_FONT_SLANT;
1402   }
1403
1404   FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
1405   FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
1406   FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
1407
1408   // Add a property of the pattern, to say we want to match TrueType fonts
1409   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
1410
1411   // modify the config, with the mFontFamilyPatterm
1412   FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
1413
1414   // provide default values for unspecified properties in the font pattern
1415   // e.g. patterns without a specified style or weight are set to Medium
1416   FcDefaultSubstitute( fontFamilyPattern );
1417
1418   return fontFamilyPattern;
1419 }
1420
1421 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
1422 {
1423   // create a new pattern.
1424   // a pattern holds a set of names, each name refers to a property of the font
1425   FcPattern* pattern = FcPatternCreate();
1426
1427   FcFontSet* fontset = NULL;
1428
1429   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
1430   FcObjectSet* objectSet = FcObjectSetCreate();
1431
1432   if( objectSet )
1433   {
1434     // build an object set from a list of property names
1435     FcObjectSetAdd( objectSet, FC_FILE );
1436     FcObjectSetAdd( objectSet, FC_FAMILY );
1437     FcObjectSetAdd( objectSet, FC_WIDTH );
1438     FcObjectSetAdd( objectSet, FC_WEIGHT );
1439     FcObjectSetAdd( objectSet, FC_SLANT );
1440
1441     // get a list of fonts
1442     // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
1443     fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
1444
1445     // clear up the object set
1446     FcObjectSetDestroy( objectSet );
1447   }
1448   // clear up the pattern
1449   if( pattern )
1450   {
1451     FcPatternDestroy( pattern );
1452   }
1453
1454   return fontset;
1455 }
1456
1457 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1458                                       const char* const n,
1459                                       std::string& string )
1460 {
1461   FcChar8* file = NULL;
1462   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1463
1464   if( FcResultMatch == retVal )
1465   {
1466     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1467     string.assign( reinterpret_cast<const char*>( file ) );
1468
1469     return true;
1470   }
1471
1472   return false;
1473 }
1474
1475 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
1476 {
1477   const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
1478
1479   if( FcResultMatch == retVal )
1480   {
1481     return true;
1482   }
1483
1484   return false;
1485 }
1486
1487 FontId FontClient::Plugin::CreateFont( const FontPath& path,
1488                                        PointSize26Dot6 requestedPointSize,
1489                                        FaceIndex faceIndex,
1490                                        bool cacheDescription )
1491 {
1492   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::CreateFont\n" );
1493   DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
1494   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1495
1496   FontId id = 0u;
1497
1498   // Create & cache new font face
1499   FT_Face ftFace;
1500   int error = FT_New_Face( mFreeTypeLibrary,
1501                            path.c_str(),
1502                            0,
1503                            &ftFace );
1504
1505   if( FT_Err_Ok == error )
1506   {
1507     // Check if a font is scalable.
1508     const bool isScalable = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_SCALABLE ) );
1509     const bool hasFixedSizedBitmaps = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_FIXED_SIZES ) ) && ( 0 != ftFace->num_fixed_sizes );
1510     const bool hasColorTables = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_COLOR ) );
1511
1512     DALI_LOG_INFO( gLogFilter, Debug::General, "            isScalable : [%s]\n", ( isScalable ? "true" : "false" ) );
1513     DALI_LOG_INFO( gLogFilter, Debug::General, "  hasFixedSizedBitmaps : [%s]\n", ( hasFixedSizedBitmaps ? "true" : "false" ) );
1514     DALI_LOG_INFO( gLogFilter, Debug::General, "        hasColorTables : [%s]\n", ( hasColorTables ? "true" : "false" ) );
1515
1516     // Check to see if the font contains fixed sizes?
1517     if( !isScalable && hasFixedSizedBitmaps )
1518     {
1519       PointSize26Dot6 actualPointSize = 0u;
1520       int fixedSizeIndex = 0;
1521       for( ; fixedSizeIndex < ftFace->num_fixed_sizes; ++fixedSizeIndex )
1522       {
1523         const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size;
1524         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  size index : %d, size : %d\n", fixedSizeIndex, fixedSize );
1525
1526         if( fixedSize >= requestedPointSize )
1527         {
1528           actualPointSize = fixedSize;
1529           break;
1530         }
1531       }
1532
1533       if( 0u == actualPointSize )
1534       {
1535         // The requested point size is bigger than the bigest fixed size.
1536         fixedSizeIndex = ftFace->num_fixed_sizes - 1;
1537         actualPointSize = ftFace->available_sizes[fixedSizeIndex].size;
1538       }
1539
1540       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize );
1541
1542       // Tell Freetype to use this size
1543       error = FT_Select_Size( ftFace, fixedSizeIndex );
1544       if ( FT_Err_Ok != error )
1545       {
1546         DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Select_Size error: %d\n", error );
1547       }
1548       else
1549       {
1550         float fixedWidth  = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].width );
1551         float fixedHeight = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].height );
1552
1553         // Indicate that the font is a fixed sized bitmap
1554         FontMetrics metrics( fixedHeight, // The ascender in pixels.
1555                              0.0f,
1556                              fixedHeight, // The height in pixels.
1557                              0.0f,
1558                              0.0f );
1559
1560         mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedWidth, fixedHeight, hasColorTables ) );
1561         id = mFontCache.size();
1562       }
1563     }
1564     else
1565     {
1566       error = FT_Set_Char_Size( ftFace,
1567                                 0,
1568                                 requestedPointSize,
1569                                 mDpiHorizontal,
1570                                 mDpiVertical );
1571
1572       if( FT_Err_Ok == error )
1573       {
1574
1575         FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1576
1577         FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
1578                              static_cast< float >( ftMetrics.descender ) * FROM_266,
1579                              static_cast< float >( ftMetrics.height    ) * FROM_266,
1580                              static_cast< float >( ftFace->underline_position ) * FROM_266,
1581                              static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1582
1583         mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics ) );
1584         id = mFontCache.size();
1585       }
1586       else
1587       {
1588         DALI_LOG_INFO( gLogFilter, Debug::General, "  FreeType Set_Char_Size error: %d for pointSize %d\n", error, requestedPointSize );
1589       }
1590     }
1591
1592     if( 0u != id )
1593     {
1594       if( cacheDescription )
1595       {
1596         CacheFontPath( ftFace, id, requestedPointSize, path );
1597       }
1598     }
1599   }
1600   else
1601   {
1602     DALI_LOG_INFO( gLogFilter, Debug::General, "  FreeType New_Face error: %d for [%s]\n", error, path.c_str() );
1603   }
1604
1605   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
1606   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::CreateFont\n" );
1607
1608   return id;
1609 }
1610
1611 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap )
1612 {
1613   if( srcBitmap.width*srcBitmap.rows > 0 )
1614   {
1615     switch( srcBitmap.pixel_mode )
1616     {
1617       case FT_PIXEL_MODE_GRAY:
1618       {
1619         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
1620         {
1621           const unsigned int bufferSize = srcBitmap.width * srcBitmap.rows;
1622           data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1623           data.width = srcBitmap.width;
1624           data.height = srcBitmap.rows;
1625           data.format = Pixel::L8;
1626           memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1627         }
1628         break;
1629       }
1630
1631 #ifdef FREETYPE_BITMAP_SUPPORT
1632       case FT_PIXEL_MODE_BGRA:
1633       {
1634         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
1635         {
1636           // Set the input dimensions.
1637           const ImageDimensions inputDimensions( srcBitmap.width, srcBitmap.rows );
1638
1639           // Set the output dimensions.
1640           // If the output dimension is not given, the input dimension is set
1641           // and won't be downscaling.
1642           data.width = ( data.width == 0 ) ? srcBitmap.width : data.width;
1643           data.height = ( data.height == 0 ) ? srcBitmap.rows : data.height;
1644           const ImageDimensions desiredDimensions( data.width, data.height );
1645
1646           // Creates the output buffer
1647           const unsigned int bufferSize = data.width * data.height * 4u;
1648           data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1649
1650           if( inputDimensions == desiredDimensions )
1651           {
1652             // There isn't downscaling.
1653             memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1654           }
1655           else
1656           {
1657             Dali::Internal::Platform::LanczosSample4BPP( srcBitmap.buffer,
1658                                                          inputDimensions,
1659                                                          data.buffer,
1660                                                          desiredDimensions );
1661           }
1662           data.format = Pixel::BGRA8888;
1663         }
1664         break;
1665       }
1666 #endif
1667       default:
1668       {
1669         DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::ConvertBitmap. FontClient Unable to create Bitmap of this PixelType\n" );
1670         break;
1671       }
1672     }
1673   }
1674 }
1675
1676 bool FontClient::Plugin::FindFont( const FontPath& path,
1677                                    PointSize26Dot6 requestedPointSize,
1678                                    FaceIndex faceIndex,
1679                                    FontId& fontId ) const
1680 {
1681   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
1682   DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
1683   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1684   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of fonts in the cache : %d\n", mFontCache.size() );
1685
1686   fontId = 0u;
1687   for( std::vector<FontFaceCacheItem>::const_iterator it = mFontCache.begin(),
1688          endIt = mFontCache.end();
1689        it != endIt;
1690        ++it, ++fontId )
1691   {
1692     const FontFaceCacheItem& cacheItem = *it;
1693
1694     if( cacheItem.mRequestedPointSize == requestedPointSize &&
1695         cacheItem.mFaceIndex == faceIndex &&
1696         cacheItem.mPath == path )
1697     {
1698       ++fontId;
1699
1700       DALI_LOG_INFO( gLogFilter, Debug::General, "  font found, id : %d\n", fontId );
1701       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1702
1703       return true;
1704     }
1705   }
1706
1707   DALI_LOG_INFO( gLogFilter, Debug::General, "  font not found\n" );
1708   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1709
1710   return false;
1711 }
1712
1713 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1714                                             FontDescriptionId& validatedFontId )
1715 {
1716   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindValidatedFont\n" );
1717   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1718   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1719   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1720   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1721   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1722   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of validated fonts in the cache : %d\n", mValidatedFontCache.size() );
1723
1724   validatedFontId = 0u;
1725
1726   for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
1727          endIt = mValidatedFontCache.end();
1728        it != endIt;
1729        ++it )
1730   {
1731     const FontDescriptionCacheItem& item = *it;
1732
1733     if( !fontDescription.family.empty() &&
1734         ( fontDescription.family == item.fontDescription.family ) &&
1735         ( fontDescription.width == item.fontDescription.width ) &&
1736         ( fontDescription.weight == item.fontDescription.weight ) &&
1737         ( fontDescription.slant == item.fontDescription.slant ) )
1738     {
1739       validatedFontId = item.index;
1740
1741       DALI_LOG_INFO( gLogFilter, Debug::General, "  validated font found, id : %d\n", validatedFontId );
1742       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
1743       return true;
1744     }
1745   }
1746
1747   DALI_LOG_INFO( gLogFilter, Debug::General, "  validated font not found\n" );
1748   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
1749   return false;
1750 }
1751
1752 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
1753                                                FontList*& fontList,
1754                                                CharacterSetList*& characterSetList )
1755 {
1756   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFontList\n" );
1757   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1758   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1759   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1760   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1761   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1762   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of fallback font lists in the cache : %d\n", mFallbackCache.size() );
1763
1764   fontList = NULL;
1765
1766   for( std::vector<FallbackCacheItem>::const_iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
1767        it != endIt;
1768        ++it )
1769   {
1770     const FallbackCacheItem& item = *it;
1771
1772     if( !fontDescription.family.empty() &&
1773         ( fontDescription.family == item.fontDescription.family ) &&
1774         ( fontDescription.width == item.fontDescription.width ) &&
1775         ( fontDescription.weight == item.fontDescription.weight ) &&
1776         ( fontDescription.slant == item.fontDescription.slant ) )
1777     {
1778       fontList = item.fallbackFonts;
1779       characterSetList = item.characterSets;
1780
1781       DALI_LOG_INFO( gLogFilter, Debug::General, "  fallback font list found.\n" );
1782       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
1783       return true;
1784     }
1785   }
1786
1787   DALI_LOG_INFO( gLogFilter, Debug::General, "  fallback font list not found.\n" );
1788   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
1789   return false;
1790 }
1791
1792 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1793                                    PointSize26Dot6 requestedPointSize,
1794                                    FontId& fontId )
1795 {
1796   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
1797   DALI_LOG_INFO( gLogFilter, Debug::General, "    validatedFontId  : %d\n", validatedFontId );
1798   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1799
1800   fontId = 0u;
1801
1802   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
1803          endIt = mFontIdCache.end();
1804        it != endIt;
1805        ++it )
1806   {
1807     const FontIdCacheItem& item = *it;
1808
1809     if( ( validatedFontId == item.validatedFontId ) &&
1810         ( requestedPointSize == item.requestedPointSize ) )
1811     {
1812       fontId = item.fontId;
1813
1814       DALI_LOG_INFO( gLogFilter, Debug::General, "  font found, id : %d\n", fontId );
1815       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1816       return true;
1817     }
1818   }
1819
1820   DALI_LOG_INFO( gLogFilter, Debug::General, "  font not found.\n" );
1821   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1822   return false;
1823 }
1824
1825 bool FontClient::Plugin::IsScalable( const FontPath& path )
1826 {
1827   bool isScalable = false;
1828
1829   FT_Face ftFace;
1830   int error = FT_New_Face( mFreeTypeLibrary,
1831                            path.c_str(),
1832                            0,
1833                            &ftFace );
1834   if( FT_Err_Ok != error )
1835   {
1836     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: %s\n", path.c_str() );
1837   }
1838   else
1839   {
1840     isScalable = ftFace->face_flags & FT_FACE_FLAG_SCALABLE;
1841   }
1842
1843   return isScalable;
1844 }
1845
1846 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1847 {
1848   // Create a font pattern.
1849   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1850
1851   FcResult result = FcResultMatch;
1852
1853   // match the pattern
1854   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1855   bool isScalable = false;
1856
1857   if( match )
1858   {
1859     // Get the path to the font file name.
1860     FontPath path;
1861     GetFcString( match, FC_FILE, path );
1862     isScalable = IsScalable( path );
1863   }
1864   else
1865   {
1866     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
1867   }
1868   FcPatternDestroy( fontFamilyPattern );
1869   FcPatternDestroy( match );
1870   return isScalable;
1871 }
1872
1873 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1874 {
1875   // Empty the caller container
1876   sizes.Clear();
1877
1878   FT_Face ftFace;
1879   int error = FT_New_Face( mFreeTypeLibrary,
1880                            path.c_str(),
1881                            0,
1882                            &ftFace );
1883   if( FT_Err_Ok != error )
1884   {
1885     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font path : [%s]\n", path.c_str() );
1886   }
1887
1888   // Fetch the number of fixed sizes available
1889   if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1890   {
1891     for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1892     {
1893       sizes.PushBack( ftFace->available_sizes[ i ].size );
1894     }
1895   }
1896 }
1897
1898 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1899                                         Vector< PointSize26Dot6 >& sizes )
1900 {
1901   // Create a font pattern.
1902   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1903
1904   FcResult result = FcResultMatch;
1905
1906   // match the pattern
1907   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1908
1909   if( match )
1910   {
1911     // Get the path to the font file name.
1912     FontPath path;
1913     GetFcString( match, FC_FILE, path );
1914     GetFixedSizes( path, sizes );
1915   }
1916   else
1917   {
1918     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
1919   }
1920   FcPatternDestroy( match );
1921   FcPatternDestroy( fontFamilyPattern );
1922 }
1923
1924 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize,  const FontPath& path )
1925 {
1926   FontDescription description;
1927   description.path = path;
1928   description.family = FontFamily( ftFace->family_name );
1929   description.weight = FontWeight::NONE;
1930   description.width = FontWidth::NONE;
1931   description.slant = FontSlant::NONE;
1932
1933   // Note FreeType doesn't give too much info to build a proper font style.
1934   if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1935   {
1936     description.slant = FontSlant::ITALIC;
1937   }
1938   if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1939   {
1940     description.weight = FontWeight::BOLD;
1941   }
1942
1943   FontDescriptionId validatedFontId = 0u;
1944   if( !FindValidatedFont( description,
1945                           validatedFontId ) )
1946   {
1947     // Set the index to the vector of paths to font file names.
1948     validatedFontId = mFontDescriptionCache.size();
1949
1950     FcPattern* pattern = CreateFontFamilyPattern( description );
1951
1952     FcResult result = FcResultMatch;
1953     FcPattern* match = FcFontMatch( NULL, pattern, &result );
1954
1955     FcCharSet* characterSet = NULL;
1956     FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
1957
1958     FcPatternDestroy( match );
1959     FcPatternDestroy( pattern );
1960
1961     mFontCache[id-1u].mCharacterSet = characterSet;
1962
1963     // Add the path to the cache.
1964     mFontDescriptionCache.push_back( description );
1965     mCharacterSetCache.PushBack( characterSet );
1966
1967     // Cache the index and the font's description.
1968     FontDescriptionCacheItem item( description,
1969                                    validatedFontId );
1970
1971     mValidatedFontCache.push_back( item );
1972
1973     // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
1974     mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
1975                                              requestedPointSize,
1976                                              id ) );
1977   }
1978 }
1979
1980 FcCharSet* FontClient::Plugin::CreateCharacterSetFromDescription( const FontDescription& description ) const
1981 {
1982   FcCharSet* characterSet = NULL;
1983
1984   FcPattern* pattern = CreateFontFamilyPattern( description );
1985
1986   if( NULL != pattern )
1987   {
1988     FcResult result = FcResultMatch;
1989     FcPattern* match = FcFontMatch( NULL, pattern, &result );
1990
1991     FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
1992
1993     FcPatternDestroy( match );
1994     FcPatternDestroy( pattern );
1995   }
1996
1997   return characterSet;
1998 }
1999
2000 } // namespace Internal
2001
2002 } // namespace TextAbstraction
2003
2004 } // namespace Dali