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