Merge remote-tracking branch 'origin/tizen' into new_text
[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/public-api/common/vector-wrapper.h>
23 #include <dali/public-api/text-abstraction/glyph-info.h>
24 #include <dali/integration-api/debug.h>
25
26 // EXTERNAL INCLUDES
27 #include <fontconfig/fontconfig.h>
28
29 /**
30  * Conversion from Fractional26.6 to float
31  */
32 namespace
33 {
34 const float FROM_266 = 1.0f / 64.0f;
35
36 const std::string FONT_FORMAT( "TrueType" );
37 const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
38 const std::string DEFAULT_FONT_STYLE( "Regular" );
39 }
40
41 namespace Dali
42 {
43
44 namespace TextAbstraction
45 {
46
47 namespace Internal
48 {
49
50 const bool FONT_FIXED_SIZE_BITMAP( true );
51
52 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontFamily& fontFamily,
53                                                                         const FontStyle& fontStyle,
54                                                                         FontDescriptionId index )
55 : fontFamily( fontFamily ),
56   fontStyle( fontStyle ),
57   index( index )
58 {}
59
60 FontClient::Plugin::FontIdCacheItem::FontIdCacheItem( FontDescriptionId validatedFontId,
61                                                       PointSize26Dot6 pointSize,
62                                                       FontId fontId )
63 : validatedFontId( validatedFontId ),
64   pointSize( pointSize ),
65   fontId( fontId )
66 {}
67
68 FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
69                                           const FontPath& path,
70                                           PointSize26Dot6 pointSize,
71                                           FaceIndex face,
72                                           const FontMetrics& metrics,
73                                           bool isFixedSizeBitmap )
74 : mFreeTypeFace( ftFace ),
75   mPath( path ),
76   mPointSize( pointSize ),
77   mFaceIndex( face ),
78   mMetrics( metrics ),
79   mIsFixedSizeBitmap( isFixedSizeBitmap )
80 {}
81
82 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
83                             unsigned int verticalDpi )
84 : mFreeTypeLibrary( NULL ),
85   mDpiHorizontal( horizontalDpi ),
86   mDpiVertical( verticalDpi ),
87   mSystemFonts(),
88   mDefaultFonts(),
89   mFontCache(),
90   mValidatedFontCache(),
91   mFontDescriptionCache( 1u ),
92   mFontIdCache()
93 {
94   int error = FT_Init_FreeType( &mFreeTypeLibrary );
95   if( FT_Err_Ok != error )
96   {
97     DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
98   }
99 }
100
101 FontClient::Plugin::~Plugin()
102 {
103   FT_Done_FreeType( mFreeTypeLibrary );
104 }
105
106 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
107                                  unsigned int verticalDpi )
108 {
109   mDpiHorizontal = horizontalDpi;
110   mDpiVertical = verticalDpi;
111 }
112
113 void FontClient::Plugin::SetDefaultFontFamily( const FontFamily& fontFamilyName,
114                                                const FontStyle& fontStyle )
115 {
116   mDefaultFonts.clear();
117
118   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamilyName,
119                                                           fontStyle );
120
121   FcResult result = FcResultMatch;
122
123   // Match the pattern.
124   FcFontSet* fontSet = FcFontSort( NULL /* use default configure */,
125                                    fontFamilyPattern,
126                                    false /* don't trim */,
127                                    NULL,
128                                    &result );
129
130   if( NULL != fontSet )
131   {
132     // Reserve some space to avoid reallocations.
133     mDefaultFonts.reserve( fontSet->nfont );
134
135     for( int i = 0u; i < fontSet->nfont; ++i )
136     {
137       FcPattern* fontPattern = fontSet->fonts[i];
138
139       FontPath path;
140
141       // Skip fonts with no path
142       if( GetFcString( fontPattern, FC_FILE, path ) )
143       {
144         mDefaultFonts.push_back( FontDescription() );
145         FontDescription& fontDescription = mDefaultFonts.back();
146
147         fontDescription.path = path;
148
149         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
150         GetFcString( fontPattern, FC_STYLE, fontDescription.style );
151       }
152     }
153
154     FcFontSetDestroy( fontSet );
155   }
156
157   FcPatternDestroy( fontFamilyPattern );
158 }
159
160 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
161 {
162   if( mDefaultFonts.empty() )
163   {
164     SetDefaultFontFamily( DEFAULT_FONT_FAMILY_NAME,
165                           DEFAULT_FONT_STYLE );
166   }
167
168   defaultFonts = mDefaultFonts;
169 }
170
171 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
172 {
173   if( mSystemFonts.empty() )
174   {
175     InitSystemFonts();
176   }
177
178   systemFonts = mSystemFonts;
179 }
180
181 void FontClient::Plugin::GetDescription( FontId id,
182                                          FontDescription& fontDescription ) const
183 {
184   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
185          endIt = mFontIdCache.end();
186        it != endIt;
187        ++it )
188   {
189     const FontIdCacheItem& item = *it;
190
191     if( item.fontId == id )
192     {
193       fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
194       return;
195     }
196   }
197
198   DALI_LOG_ERROR( "FontClient::Plugin::GetDescription. No description found for the font ID %d\n", id );
199 }
200
201 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
202 {
203   const FontId index = id - 1u;
204
205   if( id > 0u &&
206       index < mFontCache.size() )
207   {
208     return ( *( mFontCache.begin() + index ) ).mPointSize;
209   }
210   else
211   {
212     DALI_LOG_ERROR( "FontClient::Plugin::GetPointSize. Invalid font ID %d\n", id );
213   }
214
215   return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
216 }
217
218 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
219                                             PointSize26Dot6 pointSize )
220 {
221   // Create the list of default fonts if it has not been created.
222   if( mDefaultFonts.empty() )
223   {
224     SetDefaultFontFamily( DEFAULT_FONT_FAMILY_NAME,
225                           DEFAULT_FONT_STYLE );
226   }
227
228   // Traverse the list of default fonts.
229   // Check for each default font if supports the character.
230
231   for( FontList::const_iterator it = mDefaultFonts.begin(),
232          endIt = mDefaultFonts.end();
233        it != endIt;
234        ++it )
235   {
236     const FontDescription& description = *it;
237
238     FcPattern* pattern = CreateFontFamilyPattern( description.family,
239                                                   description.style );
240
241     FcResult result = FcResultMatch;
242     FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
243
244     FcCharSet* charSet = NULL;
245     FcPatternGetCharSet( match, FC_CHARSET, 0u, &charSet );
246
247     if( FcCharSetHasChar( charSet, charcode ) )
248     {
249       return GetFontId( description.family,
250                         description.style,
251                         pointSize,
252                         0u );
253     }
254   }
255
256   return 0u;
257 }
258
259 FontId FontClient::Plugin::GetFontId( const FontPath& path,
260                                       PointSize26Dot6 pointSize,
261                                       FaceIndex faceIndex,
262                                       bool cacheDescription )
263 {
264   FontId id( 0 );
265
266   if( NULL != mFreeTypeLibrary )
267   {
268     FontId foundId(0);
269     if( FindFont( path, pointSize, faceIndex, foundId ) )
270     {
271       id = foundId;
272     }
273     else
274     {
275       id = CreateFont( path, pointSize, faceIndex, cacheDescription );
276     }
277   }
278
279   return id;
280 }
281
282 FontId FontClient::Plugin::GetFontId( const FontFamily& fontFamily,
283                                       const FontStyle& fontStyle,
284                                       PointSize26Dot6 pointSize,
285                                       FaceIndex faceIndex )
286 {
287   // This method uses three vectors which caches:
288   // * Pairs of non validated 'fontFamily, fontStyle' and an index to a vector with paths to font file names.
289   // * The path to font file names.
290   // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
291
292   // 1) Checks in the cache if the pair 'fontFamily, fontStyle' has been validated before.
293   //    If it was it gets an index to the vector with paths to font file names. Otherwise,
294   //    retrieves using font config a path to a font file name which matches with the pair
295   //    'fontFamily, fontStyle'. The path is stored in the chache.
296   //
297   // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
298   //    fon file names' exists. If exists, it gets the font id. If it doesn't it calls
299   //    the GetFontId() method with the path to the font file name and the point size to
300   //    get the font id.
301
302   // The font id to be returned.
303   FontId fontId = 0u;
304
305   // Check first if the pair font family and style have been validated before.
306   FontDescriptionId validatedFontId = 0u;
307
308   if( !FindValidatedFont( fontFamily,
309                           fontStyle,
310                           validatedFontId ) )
311   {
312     // Use font config to validate the font family name and font style.
313     ValidateFont( fontFamily, fontStyle, validatedFontId );
314   }
315
316   // Check if exists a pair 'validatedFontId, pointSize' in the cache.
317   if( !FindFont( validatedFontId, pointSize, fontId ) )
318   {
319     // Retrieve the font file name path.
320     const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
321
322     // Retrieve the font id. Do not cache the description as it has been already cached.
323     fontId = GetFontId( description.path,
324                         pointSize,
325                         faceIndex,
326                         false );
327
328     // Cache the pair 'validatedFontId, pointSize' to improve the following queries.
329     mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
330                                              pointSize,
331                                              fontId ) );
332   }
333
334   return fontId;
335 }
336
337 void FontClient::Plugin::ValidateFont( const FontFamily& fontFamily,
338                                        const FontStyle& fontStyle,
339                                        FontDescriptionId& validatedFontId )
340 {
341   // Create a font pattern.
342   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamily,
343                                                             fontStyle );
344
345   FcResult result = FcResultMatch;
346
347   // match the pattern
348   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
349
350   if( match )
351   {
352     // Get the path to the font file name.
353     FontDescription description;
354     GetFcString( match, FC_FILE, description.path );
355     GetFcString( match, FC_FAMILY, description.family );
356     GetFcString( match, FC_STYLE, description.style );
357
358     // Set the index to the vector of paths to font file names.
359     validatedFontId = mFontDescriptionCache.size();
360
361     // Add the path to the cache.
362     mFontDescriptionCache.push_back( description );
363
364     // Cache the index and the pair font family name, font style.
365     FontDescriptionCacheItem item( fontFamily, fontStyle, validatedFontId );
366     mValidatedFontCache.push_back( item );
367
368     // destroyed the matched pattern
369     FcPatternDestroy( match );
370   }
371   else
372   {
373     DALI_LOG_ERROR( "FontClient::Plugin::ValidateFont failed for font %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
374   }
375
376   // destroy the pattern
377   FcPatternDestroy( fontFamilyPattern );
378 }
379
380
381
382 void FontClient::Plugin::GetFontMetrics( FontId fontId,
383                                          FontMetrics& metrics )
384 {
385   if( fontId > 0 &&
386       fontId-1 < mFontCache.size() )
387   {
388     metrics = mFontCache[fontId-1].mMetrics;
389   }
390   else
391   {
392     DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
393   }
394 }
395
396 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
397                                               Character charcode )
398 {
399   GlyphIndex index( 0 );
400
401   if( fontId > 0 &&
402       fontId-1 < mFontCache.size() )
403   {
404     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
405
406     index = FT_Get_Char_Index( ftFace, charcode );
407   }
408
409   return index;
410 }
411
412 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
413                                           uint32_t size,
414                                           bool horizontal )
415 {
416   bool success( true );
417
418   for( unsigned int i=0; i<size; ++i )
419   {
420     FontId fontId = array[i].fontId;
421
422     if( fontId > 0 &&
423         fontId-1 < mFontCache.size() )
424     {
425       FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
426
427       // Check to see if we should be loading a Fixed Size bitmap?
428       if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
429       {
430         int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_COLOR );
431         if ( FT_Err_Ok == error )
432         {
433           // TODO passing height for metrics, should store width, height and advance
434
435           float height = mFontCache[ fontId -1 ].mMetrics.height;
436           array[i].width = height;
437           array[i].height = height;
438           array[i].advance = height;
439           array[i].xBearing = 0.0f;
440           array[i].yBearing = 0.0f;
441           return success;
442         }
443         else
444         {
445           DALI_LOG_ERROR( "FreeType Bitmap Load_Glyph error %d\n", error );
446           return false;
447         }
448       }
449
450       int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
451
452       if( FT_Err_Ok == error )
453       {
454         array[i].width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
455         array[i].height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
456         if( horizontal )
457         {
458           array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
459           array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
460           array[i].advance  = static_cast< float >( ftFace->glyph->metrics.horiAdvance ) * FROM_266;
461         }
462         else
463         {
464           array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
465           array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
466           array[i].advance  = static_cast< float >( ftFace->glyph->metrics.vertAdvance ) * FROM_266;
467         }
468       }
469       else
470       {
471         success = false;
472       }
473     }
474     else
475     {
476       success = false;
477     }
478   }
479
480   return success;
481 }
482
483 BufferImage FontClient::Plugin::CreateBitmap( FontId fontId,
484                                               GlyphIndex glyphIndex )
485 {
486   BufferImage bitmap;
487
488   if( fontId > 0 &&
489       fontId-1 < mFontCache.size() )
490   {
491     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
492
493     FT_Error error;
494
495     // Check to see if this is fixed size bitmap
496     if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
497     {
498       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
499     }
500     else
501     {
502       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
503     }
504     if( FT_Err_Ok == error )
505     {
506       FT_Glyph glyph;
507       error = FT_Get_Glyph( ftFace->glyph, &glyph );
508
509       // Convert to bitmap if necessary
510       if ( FT_Err_Ok == error )
511       {
512         if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
513         {
514           error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
515           if ( FT_Err_Ok == error )
516           {
517             FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
518             ConvertBitmap( bitmap, bitmapGlyph->bitmap );
519           }
520           else
521           {
522             DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
523           }
524         }
525         else
526         {
527           ConvertBitmap( bitmap, ftFace->glyph->bitmap );
528         }
529
530         // Created FT_Glyph object must be released with FT_Done_Glyph
531         FT_Done_Glyph( glyph );
532       }
533     }
534     else
535     {
536       DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
537     }
538   }
539
540   return bitmap;
541 }
542
543 void FontClient::Plugin::InitSystemFonts()
544 {
545   FcFontSet* fontSet = GetFcFontSet();
546
547   if( fontSet )
548   {
549     // Reserve some space to avoid reallocations.
550     mSystemFonts.reserve( fontSet->nfont );
551
552     for( int i = 0u; i < fontSet->nfont; ++i )
553     {
554       FcPattern* fontPattern = fontSet->fonts[i];
555
556       FontPath path;
557
558       // Skip fonts with no path
559       if( GetFcString( fontPattern, FC_FILE, path ) )
560       {
561         mSystemFonts.push_back( FontDescription() );
562         FontDescription& fontDescription = mSystemFonts.back();
563
564         fontDescription.path = path;
565
566         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
567         GetFcString( fontPattern, FC_STYLE, fontDescription.style );
568       }
569     }
570
571     FcFontSetDestroy( fontSet );
572   }
573 }
574
575 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontFamily& fontFamily,
576                                                         const FontStyle& fontStyle )
577 {
578   // create the cached font family lookup pattern
579   // a pattern holds a set of names, each name refers to a property of the font
580   FcPattern* fontFamilyPattern = FcPatternCreate();
581
582   // add a property to the pattern for the font family
583   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontFamily.c_str() ) );
584
585   // add a property to the pattern for the font family
586   FcPatternAddString( fontFamilyPattern, FC_STYLE, reinterpret_cast<const FcChar8*>( fontStyle.c_str() ) );
587
588   // Add a property of the pattern, to say we want to match TrueType fonts
589   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
590
591   // modify the config, with the mFontFamilyPatterm
592   FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
593
594   // provide default values for unspecified properties in the font pattern
595   // e.g. patterns without a specified style or weight are set to Medium
596   FcDefaultSubstitute( fontFamilyPattern );
597
598   return fontFamilyPattern;
599 }
600
601 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
602 {
603   // create a new pattern.
604   // a pattern holds a set of names, each name refers to a property of the font
605   FcPattern* pattern = FcPatternCreate();
606
607   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
608   FcObjectSet* objectSet = FcObjectSetCreate();
609
610   // build an object set from a list of property names
611   FcObjectSetAdd( objectSet, FC_FILE );
612   FcObjectSetAdd( objectSet, FC_FAMILY );
613   FcObjectSetAdd( objectSet, FC_STYLE );
614
615   // get a list of fonts
616   // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
617   FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
618
619   // clear up the object set
620   if( objectSet )
621   {
622     FcObjectSetDestroy( objectSet );
623   }
624   // clear up the pattern
625   if( pattern )
626   {
627     FcPatternDestroy( pattern );
628   }
629
630   return fontset;
631 }
632
633 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
634                                       const char* const n,
635                                       std::string& string )
636 {
637   FcChar8* file = NULL;
638   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
639
640   if( FcResultMatch == retVal )
641   {
642     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
643     string.assign( reinterpret_cast<const char*>( file ) );
644
645     return true;
646   }
647
648   return false;
649 }
650
651 FontId FontClient::Plugin::CreateFont( const FontPath& path,
652                                        PointSize26Dot6 pointSize,
653                                        FaceIndex faceIndex,
654                                        bool cacheDescription )
655 {
656   FontId id( 0 );
657
658   // Create & cache new font face
659   FT_Face ftFace;
660   int error = FT_New_Face( mFreeTypeLibrary,
661                            path.c_str(),
662                            0,
663                            &ftFace );
664
665   if( FT_Err_Ok == error )
666   {
667     // Check to see if the font contains fixed sizes?
668     if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
669     {
670       // Ensure this size is available
671       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
672       {
673         if ( pointSize == ftFace->available_sizes[ i ].size )
674         {
675           // Tell Freetype to use this size
676           error = FT_Select_Size( ftFace, i );
677           if ( FT_Err_Ok != error )
678           {
679             DALI_LOG_ERROR( "FreeType Select_Size error: %d\n", error );
680           }
681           else
682           {
683             // Indicate that the font is a fixed sized bitmap
684             FontMetrics metrics( 0.0f,
685                                  0.0f,
686                                  static_cast< float >( ftFace->available_sizes[ i ].height ) );
687
688             mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics, FONT_FIXED_SIZE_BITMAP ) );
689             id = mFontCache.size();
690
691             if( cacheDescription )
692             {
693               FontDescription description;
694               description.path = path;
695               description.family = FontFamily( ftFace->family_name );
696               description.style = FontStyle( ftFace->style_name );
697
698               mFontDescriptionCache.push_back( description );
699             }
700             return id;
701           }
702         }
703       }
704
705       // Can't find this size
706       std::stringstream sizes;
707       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
708       {
709         if ( i )
710         {
711           sizes << ", ";
712         }
713         sizes << ftFace->available_sizes[ i ].size;
714       }
715       DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n",
716                        path.c_str(), pointSize, sizes.str().c_str() );
717     }
718     else
719     {
720       error = FT_Set_Char_Size( ftFace,
721                               0,
722                               pointSize,
723                               mDpiHorizontal,
724                               mDpiVertical );
725
726       if( FT_Err_Ok == error )
727       {
728
729         FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
730
731         FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
732                              static_cast< float >( ftMetrics.descender ) * FROM_266,
733                              static_cast< float >( ftMetrics.height    ) * FROM_266 );
734
735         mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics ) );
736         id = mFontCache.size();
737
738         if( cacheDescription )
739         {
740           FontDescription description;
741           description.path = path;
742           description.family = FontFamily( ftFace->family_name );
743           description.style = FontStyle( ftFace->style_name );
744
745           mFontDescriptionCache.push_back( description );
746         }
747       }
748       else
749       {
750         DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, pointSize );
751       }
752     }
753   }
754   else
755   {
756     DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
757   }
758
759   return id;
760 }
761
762 void FontClient::Plugin::ConvertBitmap( BufferImage& destBitmap,
763                                         FT_Bitmap srcBitmap )
764 {
765   if( srcBitmap.width*srcBitmap.rows > 0 )
766   {
767     switch( srcBitmap.pixel_mode )
768     {
769       case FT_PIXEL_MODE_GRAY:
770       {
771         if( srcBitmap.pitch == static_cast< int >( srcBitmap.width ) )
772         {
773           destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
774
775           PixelBuffer* destBuffer = destBitmap.GetBuffer();
776           memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
777         }
778         break;
779       }
780
781       case FT_PIXEL_MODE_BGRA:
782       {
783         if ( srcBitmap.pitch == static_cast< int >( srcBitmap.width << 2 ) )
784         {
785           destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::BGRA8888 );
786
787           PixelBuffer* destBuffer = destBitmap.GetBuffer();
788           memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows*4 );
789         }
790         break;
791       }
792       default:
793       {
794         DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" );
795         break;
796       }
797     }
798   }
799 }
800
801 bool FontClient::Plugin::FindFont( const FontPath& path,
802                                    PointSize26Dot6 pointSize,
803                                    FaceIndex faceIndex,
804                                    FontId& fontId ) const
805 {
806   fontId = 0u;
807   for( std::vector<CacheItem>::const_iterator it = mFontCache.begin(),
808          endIt = mFontCache.end();
809        it != endIt;
810        ++it, ++fontId )
811   {
812     const CacheItem& cacheItem = *it;
813
814     if( cacheItem.mPointSize == pointSize &&
815         cacheItem.mFaceIndex == faceIndex &&
816         cacheItem.mPath == path )
817     {
818       ++fontId;
819       return true;
820     }
821   }
822
823   return false;
824 }
825
826 bool FontClient::Plugin::FindValidatedFont( const FontFamily& fontFamily,
827                                             const FontStyle& fontStyle,
828                                             FontDescriptionId& validatedFontId )
829 {
830   validatedFontId = 0u;
831
832   for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
833          endIt = mValidatedFontCache.end();
834        it != endIt;
835        ++it )
836   {
837     const FontDescriptionCacheItem& item = *it;
838
839     if( ( fontFamily == item.fontFamily ) &&
840         ( fontStyle == item.fontStyle ) )
841     {
842       validatedFontId = item.index;
843
844       return true;
845     }
846   }
847
848   return false;
849 }
850
851 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
852                                    PointSize26Dot6 pointSize,
853                                    FontId& fontId )
854 {
855   fontId = 0u;
856
857   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
858          endIt = mFontIdCache.end();
859        it != endIt;
860        ++it )
861   {
862     const FontIdCacheItem& item = *it;
863
864     if( ( validatedFontId == item.validatedFontId ) &&
865         ( pointSize == item.pointSize ) )
866     {
867       fontId = item.fontId;
868       return true;
869     }
870   }
871
872   return false;
873 }
874
875 bool FontClient::Plugin::IsScalable( const FontPath& path )
876 {
877   FT_Face ftFace;
878   int error = FT_New_Face( mFreeTypeLibrary,
879                            path.c_str(),
880                            0,
881                            &ftFace );
882   if( FT_Err_Ok != error )
883   {
884     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
885   }
886   return ( ftFace->num_fixed_sizes == 0 );
887 }
888
889 bool FontClient::Plugin::IsScalable( const FontFamily& fontFamily, const FontStyle& fontStyle )
890 {
891   // Create a font pattern.
892   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamily,
893                                                           fontStyle );
894
895   FcResult result = FcResultMatch;
896
897   // match the pattern
898   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
899
900   if( match )
901   {
902     // Get the path to the font file name.
903     FontPath path;
904     GetFcString( match, FC_FILE, path );
905     return IsScalable( path );
906   }
907   DALI_LOG_ERROR( "FreeType Cannot check font: %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
908   return true;
909 }
910
911 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6 >& sizes )
912 {
913   // Empty the caller container
914   sizes.Clear();
915
916   FT_Face ftFace;
917   int error = FT_New_Face( mFreeTypeLibrary,
918                            path.c_str(),
919                            0,
920                            &ftFace );
921   if( FT_Err_Ok != error )
922   {
923     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
924   }
925
926   // Fetch the number of fixed sizes available
927   if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
928   {
929     for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
930     {
931       sizes.PushBack( ftFace->available_sizes[ i ].size );
932     }
933   }
934 }
935
936 void FontClient::Plugin::GetFixedSizes( const FontFamily& fontFamily,
937                                         const FontStyle& fontStyle,
938                                         Dali::Vector< PointSize26Dot6 >& sizes )
939 {
940   // Create a font pattern.
941   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamily,
942                                                           fontStyle );
943
944   FcResult result = FcResultMatch;
945
946   // match the pattern
947   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
948
949   if( match )
950   {
951     // Get the path to the font file name.
952     FontPath path;
953     GetFcString( match, FC_FILE, path );
954     return GetFixedSizes( path, sizes );
955   }
956   DALI_LOG_ERROR( "FreeType Cannot check font: %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
957 }
958
959 } // namespace Internal
960
961 } // namespace TextAbstraction
962
963 } // namespace Dali