65ca24ea776d1a2157c0aadba89ab321a67b24b8
[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 bool FontClient::Plugin::AddCustomFontDirectory( const FontPath& path )
1278 {
1279   // NULL as first parameter means the current configuration is used.
1280   return FcConfigAppFontAddDir( NULL, reinterpret_cast<const FcChar8 *>( path.c_str() ) );
1281 }
1282
1283 void FontClient::Plugin::InitSystemFonts()
1284 {
1285   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::InitSystemFonts\n" );
1286
1287   FcFontSet* fontSet = GetFcFontSet();
1288
1289   if( fontSet )
1290   {
1291     DALI_LOG_INFO( gLogFilter, Debug::General, "  number of system fonts : %d\n", fontSet->nfont );
1292
1293     // Reserve some space to avoid reallocations.
1294     mSystemFonts.reserve( fontSet->nfont );
1295
1296     for( int i = 0u; i < fontSet->nfont; ++i )
1297     {
1298       FcPattern* fontPattern = fontSet->fonts[i];
1299
1300       FontPath path;
1301
1302       // Skip fonts with no path
1303       if( GetFcString( fontPattern, FC_FILE, path ) )
1304       {
1305         mSystemFonts.push_back( FontDescription() );
1306         FontDescription& fontDescription = mSystemFonts.back();
1307
1308         fontDescription.path = path;
1309
1310         int width = 0;
1311         int weight = 0;
1312         int slant = 0;
1313         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
1314         GetFcInt( fontPattern, FC_WIDTH, width );
1315         GetFcInt( fontPattern, FC_WEIGHT, weight );
1316         GetFcInt( fontPattern, FC_SLANT, slant );
1317         fontDescription.width = IntToWidthType( width );
1318         fontDescription.weight = IntToWeightType( weight );
1319         fontDescription.slant = IntToSlantType( slant );
1320
1321         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  description; family : [%s]\n", fontDescription.family.c_str() );
1322         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1323         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1324         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1325         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1326       }
1327     }
1328
1329     FcFontSetDestroy( fontSet );
1330   }
1331   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::InitSystemFonts\n" );
1332 }
1333
1334 bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet )
1335 {
1336   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1337
1338   FcResult result = FcResultMatch;
1339   FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
1340
1341   const bool matched = NULL != match;
1342   DALI_LOG_INFO( gLogFilter, Debug::General, "  pattern matched : %s\n", ( matched ? "true" : "false" ) );
1343
1344   if( matched )
1345   {
1346     int width = 0;
1347     int weight = 0;
1348     int slant = 0;
1349     GetFcString( match, FC_FILE, fontDescription.path );
1350     GetFcString( match, FC_FAMILY, fontDescription.family );
1351     GetFcInt( match, FC_WIDTH, width );
1352     GetFcInt( match, FC_WEIGHT, weight );
1353     GetFcInt( match, FC_SLANT, slant );
1354     fontDescription.width = IntToWidthType( width );
1355     fontDescription.weight = IntToWeightType( weight );
1356     fontDescription.slant = IntToSlantType( slant );
1357
1358     // Cache the character ranges.
1359     FcPatternGetCharSet( match, FC_CHARSET, 0u, characterSet );
1360
1361     // destroyed the matched pattern
1362     FcPatternDestroy( match );
1363
1364     DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1365     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1366     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1367     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1368     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1369   }
1370
1371   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1372   return matched;
1373 }
1374
1375 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription ) const
1376 {
1377   // create the cached font family lookup pattern
1378   // a pattern holds a set of names, each name refers to a property of the font
1379   FcPattern* fontFamilyPattern = FcPatternCreate();
1380
1381   if( !fontFamilyPattern )
1382   {
1383     return NULL;
1384   }
1385
1386   // add a property to the pattern for the font family
1387   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
1388
1389   int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
1390   if( width < 0 )
1391   {
1392     // Use default.
1393     width = DEFAULT_FONT_WIDTH;
1394   }
1395
1396   int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
1397   if( weight < 0 )
1398   {
1399     // Use default.
1400     weight = DEFAULT_FONT_WEIGHT;
1401   }
1402
1403   int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
1404   if( slant < 0 )
1405   {
1406     // Use default.
1407     slant = DEFAULT_FONT_SLANT;
1408   }
1409
1410   FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
1411   FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
1412   FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
1413
1414   // Add a property of the pattern, to say we want to match TrueType fonts
1415   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
1416
1417   // modify the config, with the mFontFamilyPatterm
1418   FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
1419
1420   // provide default values for unspecified properties in the font pattern
1421   // e.g. patterns without a specified style or weight are set to Medium
1422   FcDefaultSubstitute( fontFamilyPattern );
1423
1424   return fontFamilyPattern;
1425 }
1426
1427 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
1428 {
1429   // create a new pattern.
1430   // a pattern holds a set of names, each name refers to a property of the font
1431   FcPattern* pattern = FcPatternCreate();
1432
1433   FcFontSet* fontset = NULL;
1434
1435   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
1436   FcObjectSet* objectSet = FcObjectSetCreate();
1437
1438   if( objectSet )
1439   {
1440     // build an object set from a list of property names
1441     FcObjectSetAdd( objectSet, FC_FILE );
1442     FcObjectSetAdd( objectSet, FC_FAMILY );
1443     FcObjectSetAdd( objectSet, FC_WIDTH );
1444     FcObjectSetAdd( objectSet, FC_WEIGHT );
1445     FcObjectSetAdd( objectSet, FC_SLANT );
1446
1447     // get a list of fonts
1448     // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
1449     fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
1450
1451     // clear up the object set
1452     FcObjectSetDestroy( objectSet );
1453   }
1454   // clear up the pattern
1455   if( pattern )
1456   {
1457     FcPatternDestroy( pattern );
1458   }
1459
1460   return fontset;
1461 }
1462
1463 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1464                                       const char* const n,
1465                                       std::string& string )
1466 {
1467   FcChar8* file = NULL;
1468   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1469
1470   if( FcResultMatch == retVal )
1471   {
1472     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1473     string.assign( reinterpret_cast<const char*>( file ) );
1474
1475     return true;
1476   }
1477
1478   return false;
1479 }
1480
1481 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
1482 {
1483   const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
1484
1485   if( FcResultMatch == retVal )
1486   {
1487     return true;
1488   }
1489
1490   return false;
1491 }
1492
1493 FontId FontClient::Plugin::CreateFont( const FontPath& path,
1494                                        PointSize26Dot6 requestedPointSize,
1495                                        FaceIndex faceIndex,
1496                                        bool cacheDescription )
1497 {
1498   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::CreateFont\n" );
1499   DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
1500   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1501
1502   FontId id = 0u;
1503
1504   // Create & cache new font face
1505   FT_Face ftFace;
1506   int error = FT_New_Face( mFreeTypeLibrary,
1507                            path.c_str(),
1508                            0,
1509                            &ftFace );
1510
1511   if( FT_Err_Ok == error )
1512   {
1513     // Check if a font is scalable.
1514     const bool isScalable = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_SCALABLE ) );
1515     const bool hasFixedSizedBitmaps = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_FIXED_SIZES ) ) && ( 0 != ftFace->num_fixed_sizes );
1516     const bool hasColorTables = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_COLOR ) );
1517
1518     DALI_LOG_INFO( gLogFilter, Debug::General, "            isScalable : [%s]\n", ( isScalable ? "true" : "false" ) );
1519     DALI_LOG_INFO( gLogFilter, Debug::General, "  hasFixedSizedBitmaps : [%s]\n", ( hasFixedSizedBitmaps ? "true" : "false" ) );
1520     DALI_LOG_INFO( gLogFilter, Debug::General, "        hasColorTables : [%s]\n", ( hasColorTables ? "true" : "false" ) );
1521
1522     // Check to see if the font contains fixed sizes?
1523     if( !isScalable && hasFixedSizedBitmaps )
1524     {
1525       PointSize26Dot6 actualPointSize = 0u;
1526       int fixedSizeIndex = 0;
1527       for( ; fixedSizeIndex < ftFace->num_fixed_sizes; ++fixedSizeIndex )
1528       {
1529         const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size;
1530         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  size index : %d, size : %d\n", fixedSizeIndex, fixedSize );
1531
1532         if( fixedSize >= requestedPointSize )
1533         {
1534           actualPointSize = fixedSize;
1535           break;
1536         }
1537       }
1538
1539       if( 0u == actualPointSize )
1540       {
1541         // The requested point size is bigger than the bigest fixed size.
1542         fixedSizeIndex = ftFace->num_fixed_sizes - 1;
1543         actualPointSize = ftFace->available_sizes[fixedSizeIndex].size;
1544       }
1545
1546       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize );
1547
1548       // Tell Freetype to use this size
1549       error = FT_Select_Size( ftFace, fixedSizeIndex );
1550       if ( FT_Err_Ok != error )
1551       {
1552         DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Select_Size error: %d\n", error );
1553       }
1554       else
1555       {
1556         float fixedWidth  = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].width );
1557         float fixedHeight = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].height );
1558
1559         // Indicate that the font is a fixed sized bitmap
1560         FontMetrics metrics( fixedHeight, // The ascender in pixels.
1561                              0.0f,
1562                              fixedHeight, // The height in pixels.
1563                              0.0f,
1564                              0.0f );
1565
1566         mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedWidth, fixedHeight, hasColorTables ) );
1567         id = mFontCache.size();
1568       }
1569     }
1570     else
1571     {
1572       error = FT_Set_Char_Size( ftFace,
1573                                 0,
1574                                 requestedPointSize,
1575                                 mDpiHorizontal,
1576                                 mDpiVertical );
1577
1578       if( FT_Err_Ok == error )
1579       {
1580
1581         FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1582
1583         FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
1584                              static_cast< float >( ftMetrics.descender ) * FROM_266,
1585                              static_cast< float >( ftMetrics.height    ) * FROM_266,
1586                              static_cast< float >( ftFace->underline_position ) * FROM_266,
1587                              static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1588
1589         mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics ) );
1590         id = mFontCache.size();
1591       }
1592       else
1593       {
1594         DALI_LOG_INFO( gLogFilter, Debug::General, "  FreeType Set_Char_Size error: %d for pointSize %d\n", error, requestedPointSize );
1595       }
1596     }
1597
1598     if( 0u != id )
1599     {
1600       if( cacheDescription )
1601       {
1602         CacheFontPath( ftFace, id, requestedPointSize, path );
1603       }
1604     }
1605   }
1606   else
1607   {
1608     DALI_LOG_INFO( gLogFilter, Debug::General, "  FreeType New_Face error: %d for [%s]\n", error, path.c_str() );
1609   }
1610
1611   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
1612   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::CreateFont\n" );
1613
1614   return id;
1615 }
1616
1617 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap )
1618 {
1619   if( srcBitmap.width*srcBitmap.rows > 0 )
1620   {
1621     switch( srcBitmap.pixel_mode )
1622     {
1623       case FT_PIXEL_MODE_GRAY:
1624       {
1625         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
1626         {
1627           const unsigned int bufferSize = srcBitmap.width * srcBitmap.rows;
1628           data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1629           data.width = srcBitmap.width;
1630           data.height = srcBitmap.rows;
1631           data.format = Pixel::L8;
1632           memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1633         }
1634         break;
1635       }
1636
1637 #ifdef FREETYPE_BITMAP_SUPPORT
1638       case FT_PIXEL_MODE_BGRA:
1639       {
1640         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
1641         {
1642           // Set the input dimensions.
1643           const ImageDimensions inputDimensions( srcBitmap.width, srcBitmap.rows );
1644
1645           // Set the output dimensions.
1646           // If the output dimension is not given, the input dimension is set
1647           // and won't be downscaling.
1648           data.width = ( data.width == 0 ) ? srcBitmap.width : data.width;
1649           data.height = ( data.height == 0 ) ? srcBitmap.rows : data.height;
1650           const ImageDimensions desiredDimensions( data.width, data.height );
1651
1652           // Creates the output buffer
1653           const unsigned int bufferSize = data.width * data.height * 4u;
1654           data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1655
1656           if( inputDimensions == desiredDimensions )
1657           {
1658             // There isn't downscaling.
1659             memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1660           }
1661           else
1662           {
1663             Dali::Internal::Platform::LanczosSample4BPP( srcBitmap.buffer,
1664                                                          inputDimensions,
1665                                                          data.buffer,
1666                                                          desiredDimensions );
1667           }
1668           data.format = Pixel::BGRA8888;
1669         }
1670         break;
1671       }
1672 #endif
1673       default:
1674       {
1675         DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::ConvertBitmap. FontClient Unable to create Bitmap of this PixelType\n" );
1676         break;
1677       }
1678     }
1679   }
1680 }
1681
1682 bool FontClient::Plugin::FindFont( const FontPath& path,
1683                                    PointSize26Dot6 requestedPointSize,
1684                                    FaceIndex faceIndex,
1685                                    FontId& fontId ) const
1686 {
1687   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
1688   DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
1689   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1690   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of fonts in the cache : %d\n", mFontCache.size() );
1691
1692   fontId = 0u;
1693   for( std::vector<FontFaceCacheItem>::const_iterator it = mFontCache.begin(),
1694          endIt = mFontCache.end();
1695        it != endIt;
1696        ++it, ++fontId )
1697   {
1698     const FontFaceCacheItem& cacheItem = *it;
1699
1700     if( cacheItem.mRequestedPointSize == requestedPointSize &&
1701         cacheItem.mFaceIndex == faceIndex &&
1702         cacheItem.mPath == path )
1703     {
1704       ++fontId;
1705
1706       DALI_LOG_INFO( gLogFilter, Debug::General, "  font found, id : %d\n", fontId );
1707       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1708
1709       return true;
1710     }
1711   }
1712
1713   DALI_LOG_INFO( gLogFilter, Debug::General, "  font not found\n" );
1714   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1715
1716   return false;
1717 }
1718
1719 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1720                                             FontDescriptionId& validatedFontId )
1721 {
1722   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindValidatedFont\n" );
1723   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1724   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1725   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1726   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1727   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1728   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of validated fonts in the cache : %d\n", mValidatedFontCache.size() );
1729
1730   validatedFontId = 0u;
1731
1732   for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
1733          endIt = mValidatedFontCache.end();
1734        it != endIt;
1735        ++it )
1736   {
1737     const FontDescriptionCacheItem& item = *it;
1738
1739     if( !fontDescription.family.empty() &&
1740         ( fontDescription.family == item.fontDescription.family ) &&
1741         ( fontDescription.width == item.fontDescription.width ) &&
1742         ( fontDescription.weight == item.fontDescription.weight ) &&
1743         ( fontDescription.slant == item.fontDescription.slant ) )
1744     {
1745       validatedFontId = item.index;
1746
1747       DALI_LOG_INFO( gLogFilter, Debug::General, "  validated font found, id : %d\n", validatedFontId );
1748       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
1749       return true;
1750     }
1751   }
1752
1753   DALI_LOG_INFO( gLogFilter, Debug::General, "  validated font not found\n" );
1754   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
1755   return false;
1756 }
1757
1758 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
1759                                                FontList*& fontList,
1760                                                CharacterSetList*& characterSetList )
1761 {
1762   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFontList\n" );
1763   DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
1764   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
1765   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
1766   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1767   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1768   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of fallback font lists in the cache : %d\n", mFallbackCache.size() );
1769
1770   fontList = NULL;
1771
1772   for( std::vector<FallbackCacheItem>::const_iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
1773        it != endIt;
1774        ++it )
1775   {
1776     const FallbackCacheItem& item = *it;
1777
1778     if( !fontDescription.family.empty() &&
1779         ( fontDescription.family == item.fontDescription.family ) &&
1780         ( fontDescription.width == item.fontDescription.width ) &&
1781         ( fontDescription.weight == item.fontDescription.weight ) &&
1782         ( fontDescription.slant == item.fontDescription.slant ) )
1783     {
1784       fontList = item.fallbackFonts;
1785       characterSetList = item.characterSets;
1786
1787       DALI_LOG_INFO( gLogFilter, Debug::General, "  fallback font list found.\n" );
1788       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
1789       return true;
1790     }
1791   }
1792
1793   DALI_LOG_INFO( gLogFilter, Debug::General, "  fallback font list not found.\n" );
1794   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
1795   return false;
1796 }
1797
1798 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1799                                    PointSize26Dot6 requestedPointSize,
1800                                    FontId& fontId )
1801 {
1802   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
1803   DALI_LOG_INFO( gLogFilter, Debug::General, "    validatedFontId  : %d\n", validatedFontId );
1804   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
1805
1806   fontId = 0u;
1807
1808   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
1809          endIt = mFontIdCache.end();
1810        it != endIt;
1811        ++it )
1812   {
1813     const FontIdCacheItem& item = *it;
1814
1815     if( ( validatedFontId == item.validatedFontId ) &&
1816         ( requestedPointSize == item.requestedPointSize ) )
1817     {
1818       fontId = item.fontId;
1819
1820       DALI_LOG_INFO( gLogFilter, Debug::General, "  font found, id : %d\n", fontId );
1821       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1822       return true;
1823     }
1824   }
1825
1826   DALI_LOG_INFO( gLogFilter, Debug::General, "  font not found.\n" );
1827   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1828   return false;
1829 }
1830
1831 bool FontClient::Plugin::IsScalable( const FontPath& path )
1832 {
1833   bool isScalable = false;
1834
1835   FT_Face ftFace;
1836   int error = FT_New_Face( mFreeTypeLibrary,
1837                            path.c_str(),
1838                            0,
1839                            &ftFace );
1840   if( FT_Err_Ok != error )
1841   {
1842     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: %s\n", path.c_str() );
1843   }
1844   else
1845   {
1846     isScalable = ftFace->face_flags & FT_FACE_FLAG_SCALABLE;
1847   }
1848
1849   return isScalable;
1850 }
1851
1852 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1853 {
1854   // Create a font pattern.
1855   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1856
1857   FcResult result = FcResultMatch;
1858
1859   // match the pattern
1860   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1861   bool isScalable = false;
1862
1863   if( match )
1864   {
1865     // Get the path to the font file name.
1866     FontPath path;
1867     GetFcString( match, FC_FILE, path );
1868     isScalable = IsScalable( path );
1869   }
1870   else
1871   {
1872     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
1873   }
1874   FcPatternDestroy( fontFamilyPattern );
1875   FcPatternDestroy( match );
1876   return isScalable;
1877 }
1878
1879 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1880 {
1881   // Empty the caller container
1882   sizes.Clear();
1883
1884   FT_Face ftFace;
1885   int error = FT_New_Face( mFreeTypeLibrary,
1886                            path.c_str(),
1887                            0,
1888                            &ftFace );
1889   if( FT_Err_Ok != error )
1890   {
1891     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font path : [%s]\n", path.c_str() );
1892   }
1893
1894   // Fetch the number of fixed sizes available
1895   if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1896   {
1897     for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1898     {
1899       sizes.PushBack( ftFace->available_sizes[ i ].size );
1900     }
1901   }
1902 }
1903
1904 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1905                                         Vector< PointSize26Dot6 >& sizes )
1906 {
1907   // Create a font pattern.
1908   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1909
1910   FcResult result = FcResultMatch;
1911
1912   // match the pattern
1913   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1914
1915   if( match )
1916   {
1917     // Get the path to the font file name.
1918     FontPath path;
1919     GetFcString( match, FC_FILE, path );
1920     GetFixedSizes( path, sizes );
1921   }
1922   else
1923   {
1924     DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
1925   }
1926   FcPatternDestroy( match );
1927   FcPatternDestroy( fontFamilyPattern );
1928 }
1929
1930 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize,  const FontPath& path )
1931 {
1932   FontDescription description;
1933   description.path = path;
1934   description.family = FontFamily( ftFace->family_name );
1935   description.weight = FontWeight::NONE;
1936   description.width = FontWidth::NONE;
1937   description.slant = FontSlant::NONE;
1938
1939   // Note FreeType doesn't give too much info to build a proper font style.
1940   if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1941   {
1942     description.slant = FontSlant::ITALIC;
1943   }
1944   if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1945   {
1946     description.weight = FontWeight::BOLD;
1947   }
1948
1949   FontDescriptionId validatedFontId = 0u;
1950   if( !FindValidatedFont( description,
1951                           validatedFontId ) )
1952   {
1953     // Set the index to the vector of paths to font file names.
1954     validatedFontId = mFontDescriptionCache.size();
1955
1956     FcPattern* pattern = CreateFontFamilyPattern( description );
1957
1958     FcResult result = FcResultMatch;
1959     FcPattern* match = FcFontMatch( NULL, pattern, &result );
1960
1961     FcCharSet* characterSet = NULL;
1962     FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
1963
1964     FcPatternDestroy( match );
1965     FcPatternDestroy( pattern );
1966
1967     mFontCache[id-1u].mCharacterSet = characterSet;
1968
1969     // Add the path to the cache.
1970     mFontDescriptionCache.push_back( description );
1971     mCharacterSetCache.PushBack( characterSet );
1972
1973     // Cache the index and the font's description.
1974     FontDescriptionCacheItem item( description,
1975                                    validatedFontId );
1976
1977     mValidatedFontCache.push_back( item );
1978
1979     // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
1980     mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
1981                                              requestedPointSize,
1982                                              id ) );
1983   }
1984 }
1985
1986 FcCharSet* FontClient::Plugin::CreateCharacterSetFromDescription( const FontDescription& description ) const
1987 {
1988   FcCharSet* characterSet = NULL;
1989
1990   FcPattern* pattern = CreateFontFamilyPattern( description );
1991
1992   if( NULL != pattern )
1993   {
1994     FcResult result = FcResultMatch;
1995     FcPattern* match = FcFontMatch( NULL, pattern, &result );
1996
1997     FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
1998
1999     FcPatternDestroy( match );
2000     FcPatternDestroy( pattern );
2001   }
2002
2003   return characterSet;
2004 }
2005
2006 } // namespace Internal
2007
2008 } // namespace TextAbstraction
2009
2010 } // namespace Dali