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