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/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       // Check to see if we should be loading a Fixed Size bitmap?
493       if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
494       {
495         int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_COLOR );
496         if ( FT_Err_Ok == error )
497         {
498           array[i].width = mFontCache[ fontId -1 ].mFixedWidthPixels;
499           array[i].height = mFontCache[ fontId -1 ].mFixedHeightPixels;
500           array[i].advance = mFontCache[ fontId -1 ].mFixedWidthPixels;
501           array[i].xBearing = 0.0f;
502           array[i].yBearing = mFontCache[ fontId -1 ].mFixedHeightPixels;
503         }
504         else
505         {
506           DALI_LOG_ERROR( "FreeType Bitmap Load_Glyph error %d\n", error );
507           success = false;
508         }
509       }
510       else
511       {
512         int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
513
514         if( FT_Err_Ok == error )
515         {
516           array[i].width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
517           array[i].height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
518           if( horizontal )
519           {
520             array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
521             array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
522             array[i].advance  = static_cast< float >( ftFace->glyph->metrics.horiAdvance ) * FROM_266;
523           }
524           else
525           {
526             array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
527             array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
528             array[i].advance  = static_cast< float >( ftFace->glyph->metrics.vertAdvance ) * 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     // Check to see if this is fixed size bitmap
559     if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
560     {
561       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
562     }
563     else
564     {
565       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
566     }
567     if( FT_Err_Ok == error )
568     {
569       FT_Glyph glyph;
570       error = FT_Get_Glyph( ftFace->glyph, &glyph );
571
572       // Convert to bitmap if necessary
573       if ( FT_Err_Ok == error )
574       {
575         if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
576         {
577           error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
578           if ( FT_Err_Ok == error )
579           {
580             FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
581             ConvertBitmap( bitmap, bitmapGlyph->bitmap );
582           }
583           else
584           {
585             DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
586           }
587         }
588         else
589         {
590           ConvertBitmap( bitmap, ftFace->glyph->bitmap );
591         }
592
593         // Created FT_Glyph object must be released with FT_Done_Glyph
594         FT_Done_Glyph( glyph );
595       }
596     }
597     else
598     {
599       DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
600     }
601   }
602
603   return bitmap;
604 }
605
606 void FontClient::Plugin::InitSystemFonts()
607 {
608   FcFontSet* fontSet = GetFcFontSet();
609
610   if( fontSet )
611   {
612     // Reserve some space to avoid reallocations.
613     mSystemFonts.reserve( fontSet->nfont );
614
615     for( int i = 0u; i < fontSet->nfont; ++i )
616     {
617       FcPattern* fontPattern = fontSet->fonts[i];
618
619       FontPath path;
620
621       // Skip fonts with no path
622       if( GetFcString( fontPattern, FC_FILE, path ) )
623       {
624         mSystemFonts.push_back( FontDescription() );
625         FontDescription& fontDescription = mSystemFonts.back();
626
627         fontDescription.path = path;
628
629         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
630         GetFcString( fontPattern, FC_STYLE, fontDescription.style );
631       }
632     }
633
634     FcFontSetDestroy( fontSet );
635   }
636 }
637
638 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontFamily& fontFamily,
639                                                         const FontStyle& fontStyle )
640 {
641   // create the cached font family lookup pattern
642   // a pattern holds a set of names, each name refers to a property of the font
643   FcPattern* fontFamilyPattern = FcPatternCreate();
644
645   // add a property to the pattern for the font family
646   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontFamily.c_str() ) );
647
648   // add a property to the pattern for the font family
649   FcPatternAddString( fontFamilyPattern, FC_STYLE, reinterpret_cast<const FcChar8*>( fontStyle.c_str() ) );
650
651   // Add a property of the pattern, to say we want to match TrueType fonts
652   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
653
654   // modify the config, with the mFontFamilyPatterm
655   FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
656
657   // provide default values for unspecified properties in the font pattern
658   // e.g. patterns without a specified style or weight are set to Medium
659   FcDefaultSubstitute( fontFamilyPattern );
660
661   return fontFamilyPattern;
662 }
663
664 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
665 {
666   // create a new pattern.
667   // a pattern holds a set of names, each name refers to a property of the font
668   FcPattern* pattern = FcPatternCreate();
669
670   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
671   FcObjectSet* objectSet = FcObjectSetCreate();
672
673   // build an object set from a list of property names
674   FcObjectSetAdd( objectSet, FC_FILE );
675   FcObjectSetAdd( objectSet, FC_FAMILY );
676   FcObjectSetAdd( objectSet, FC_STYLE );
677
678   // get a list of fonts
679   // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
680   FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
681
682   // clear up the object set
683   if( objectSet )
684   {
685     FcObjectSetDestroy( objectSet );
686   }
687   // clear up the pattern
688   if( pattern )
689   {
690     FcPatternDestroy( pattern );
691   }
692
693   return fontset;
694 }
695
696 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
697                                       const char* const n,
698                                       std::string& string )
699 {
700   FcChar8* file = NULL;
701   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
702
703   if( FcResultMatch == retVal )
704   {
705     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
706     string.assign( reinterpret_cast<const char*>( file ) );
707
708     return true;
709   }
710
711   return false;
712 }
713
714 FontId FontClient::Plugin::CreateFont( const FontPath& path,
715                                        PointSize26Dot6 pointSize,
716                                        FaceIndex faceIndex,
717                                        bool cacheDescription )
718 {
719   FontId id( 0 );
720
721   // Create & cache new font face
722   FT_Face ftFace;
723   int error = FT_New_Face( mFreeTypeLibrary,
724                            path.c_str(),
725                            0,
726                            &ftFace );
727
728   if( FT_Err_Ok == error )
729   {
730     // Check to see if the font contains fixed sizes?
731     if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
732     {
733       // Ensure this size is available
734       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
735       {
736         if ( static_cast<FT_Pos>(pointSize) == ftFace->available_sizes[ i ].size )
737         {
738           // Tell Freetype to use this size
739           error = FT_Select_Size( ftFace, i );
740           if ( FT_Err_Ok != error )
741           {
742             DALI_LOG_ERROR( "FreeType Select_Size error: %d\n", error );
743           }
744           else
745           {
746             float fixedWidth  = static_cast< float >( ftFace->available_sizes[ i ].width );
747             float fixedHeight = static_cast< float >( ftFace->available_sizes[ i ].height );
748
749             // Indicate that the font is a fixed sized bitmap
750             FontMetrics metrics( fixedHeight,
751                                  0.0f,
752                                  fixedHeight,
753                                  0.0f,
754                                  0.0f );
755
756             mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics, fixedWidth, fixedHeight ) );
757             id = mFontCache.size();
758
759             if( cacheDescription )
760             {
761               FontDescription description;
762               description.path = path;
763               description.family = FontFamily( ftFace->family_name );
764               description.style = FontStyle( ftFace->style_name );
765
766               mFontDescriptionCache.push_back( description );
767             }
768             return id;
769           }
770         }
771       }
772
773       // Can't find this size
774       std::stringstream sizes;
775       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
776       {
777         if ( i )
778         {
779           sizes << ", ";
780         }
781         sizes << ftFace->available_sizes[ i ].size;
782       }
783       DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n",
784                        path.c_str(), pointSize, sizes.str().c_str() );
785     }
786     else
787     {
788       error = FT_Set_Char_Size( ftFace,
789                               0,
790                               pointSize,
791                               mDpiHorizontal,
792                               mDpiVertical );
793
794       if( FT_Err_Ok == error )
795       {
796
797         FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
798
799         FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
800                              static_cast< float >( ftMetrics.descender ) * FROM_266,
801                              static_cast< float >( ftMetrics.height    ) * FROM_266,
802                              static_cast< float >( ftFace->underline_position ) * FROM_266,
803                              static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
804
805         mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics ) );
806         id = mFontCache.size();
807
808         if( cacheDescription )
809         {
810           FontDescription description;
811           description.path = path;
812           description.family = FontFamily( ftFace->family_name );
813           description.style = FontStyle( ftFace->style_name );
814
815           mFontDescriptionCache.push_back( description );
816         }
817       }
818       else
819       {
820         DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, pointSize );
821       }
822     }
823   }
824   else
825   {
826     DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
827   }
828
829   return id;
830 }
831
832 void FontClient::Plugin::ConvertBitmap( BufferImage& destBitmap,
833                                         FT_Bitmap srcBitmap )
834 {
835   if( srcBitmap.width*srcBitmap.rows > 0 )
836   {
837     switch( srcBitmap.pixel_mode )
838     {
839       case FT_PIXEL_MODE_GRAY:
840       {
841         if( srcBitmap.pitch == static_cast< int >( srcBitmap.width ) )
842         {
843           destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
844
845           PixelBuffer* destBuffer = destBitmap.GetBuffer();
846           memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
847         }
848         break;
849       }
850
851       case FT_PIXEL_MODE_BGRA:
852       {
853         if ( srcBitmap.pitch == static_cast< int >( srcBitmap.width << 2 ) )
854         {
855           destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::BGRA8888 );
856
857           PixelBuffer* destBuffer = destBitmap.GetBuffer();
858           memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows*4 );
859         }
860         break;
861       }
862       default:
863       {
864         DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" );
865         break;
866       }
867     }
868   }
869 }
870
871 bool FontClient::Plugin::FindFont( const FontPath& path,
872                                    PointSize26Dot6 pointSize,
873                                    FaceIndex faceIndex,
874                                    FontId& fontId ) const
875 {
876   fontId = 0u;
877   for( std::vector<CacheItem>::const_iterator it = mFontCache.begin(),
878          endIt = mFontCache.end();
879        it != endIt;
880        ++it, ++fontId )
881   {
882     const CacheItem& cacheItem = *it;
883
884     if( cacheItem.mPointSize == pointSize &&
885         cacheItem.mFaceIndex == faceIndex &&
886         cacheItem.mPath == path )
887     {
888       ++fontId;
889       return true;
890     }
891   }
892
893   return false;
894 }
895
896 bool FontClient::Plugin::FindValidatedFont( const FontFamily& fontFamily,
897                                             const FontStyle& fontStyle,
898                                             FontDescriptionId& validatedFontId )
899 {
900   validatedFontId = 0u;
901
902   for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
903          endIt = mValidatedFontCache.end();
904        it != endIt;
905        ++it )
906   {
907     const FontDescriptionCacheItem& item = *it;
908
909     if( ( fontFamily == item.fontFamily ) &&
910         ( fontStyle == item.fontStyle ) )
911     {
912       validatedFontId = item.index;
913
914       return true;
915     }
916   }
917
918   return false;
919 }
920
921 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
922                                    PointSize26Dot6 pointSize,
923                                    FontId& fontId )
924 {
925   fontId = 0u;
926
927   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
928          endIt = mFontIdCache.end();
929        it != endIt;
930        ++it )
931   {
932     const FontIdCacheItem& item = *it;
933
934     if( ( validatedFontId == item.validatedFontId ) &&
935         ( pointSize == item.pointSize ) )
936     {
937       fontId = item.fontId;
938       return true;
939     }
940   }
941
942   return false;
943 }
944
945 bool FontClient::Plugin::IsScalable( const FontPath& path )
946 {
947   FT_Face ftFace;
948   int error = FT_New_Face( mFreeTypeLibrary,
949                            path.c_str(),
950                            0,
951                            &ftFace );
952   if( FT_Err_Ok != error )
953   {
954     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
955   }
956   return ( ftFace->num_fixed_sizes == 0 );
957 }
958
959 bool FontClient::Plugin::IsScalable( const FontFamily& fontFamily, const FontStyle& fontStyle )
960 {
961   // Create a font pattern.
962   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamily,
963                                                           fontStyle );
964
965   FcResult result = FcResultMatch;
966
967   // match the pattern
968   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
969
970   if( match )
971   {
972     // Get the path to the font file name.
973     FontPath path;
974     GetFcString( match, FC_FILE, path );
975     return IsScalable( path );
976   }
977   DALI_LOG_ERROR( "FreeType Cannot check font: %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
978   return true;
979 }
980
981 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
982 {
983   // Empty the caller container
984   sizes.Clear();
985
986   FT_Face ftFace;
987   int error = FT_New_Face( mFreeTypeLibrary,
988                            path.c_str(),
989                            0,
990                            &ftFace );
991   if( FT_Err_Ok != error )
992   {
993     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
994   }
995
996   // Fetch the number of fixed sizes available
997   if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
998   {
999     for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1000     {
1001       sizes.PushBack( ftFace->available_sizes[ i ].size );
1002     }
1003   }
1004 }
1005
1006 void FontClient::Plugin::GetFixedSizes( const FontFamily& fontFamily,
1007                                         const FontStyle& fontStyle,
1008                                         Vector< PointSize26Dot6 >& sizes )
1009 {
1010   // Create a font pattern.
1011   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamily,
1012                                                           fontStyle );
1013
1014   FcResult result = FcResultMatch;
1015
1016   // match the pattern
1017   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1018
1019   if( match )
1020   {
1021     // Get the path to the font file name.
1022     FontPath path;
1023     GetFcString( match, FC_FILE, path );
1024     return GetFixedSizes( path, sizes );
1025   }
1026   DALI_LOG_ERROR( "FreeType Cannot check font: %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
1027 }
1028
1029 } // namespace Internal
1030
1031 } // namespace TextAbstraction
1032
1033 } // namespace Dali