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