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