Merge "Fix VD prevent issues" into devel/master
[platform/core/uifw/dali-adaptor.git] / text / dali / internal / text-abstraction / font-client-plugin-impl.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/text-abstraction/font-client-plugin-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/devel-api/text-abstraction/font-list.h>
23 #include <dali/public-api/common/dali-vector.h>
24 #include <dali/public-api/common/vector-wrapper.h>
25 #include <dali/integration-api/debug.h>
26
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 int DEFAULT_FONT_WIDTH  = 100; // normal
40 const int DEFAULT_FONT_WEIGHT =  80; // normal
41 const int DEFAULT_FONT_SLANT  =   0; // normal
42
43 const uint32_t ELLIPSIS_CHARACTER = 0x2026;
44
45 const bool FONT_FIXED_SIZE_BITMAP( true );
46
47 // http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
48
49 // ULTRA_CONDENSED 50
50 // EXTRA_CONDENSED 63
51 // CONDENSED       75
52 // SEMI_CONDENSED  87
53 // NORMAL         100
54 // SEMI_EXPANDED  113
55 // EXPANDED       125
56 // EXTRA_EXPANDED 150
57 // ULTRA_EXPANDED 200
58 const int FONT_WIDTH_TYPE_TO_INT[] = { 50, 63, 75, 87, 100, 113, 125, 150, 200 };
59 const unsigned int NUM_FONT_WIDTH_TYPE = sizeof( FONT_WIDTH_TYPE_TO_INT ) / sizeof( int );
60
61 // THIN                        0
62 // ULTRA_LIGHT, EXTRA_LIGHT   40
63 // LIGHT                      50
64 // DEMI_LIGHT, SEMI_LIGHT     55
65 // BOOK                       75
66 // NORMAL, REGULAR            80
67 // MEDIUM                    100
68 // DEMI_BOLD, SEMI_BOLD      180
69 // BOLD                      200
70 // ULTRA_BOLD, EXTRA_BOLD    205
71 // BLACK, HEAVY, EXTRA_BLACK 210
72 const int FONT_WEIGHT_TYPE_TO_INT[] = { 0, 40, 50, 55, 75, 80, 100, 180, 200, 205, 210 };
73 const unsigned int NUM_FONT_WEIGHT_TYPE = sizeof( FONT_WEIGHT_TYPE_TO_INT ) / sizeof( int );
74
75 // NORMAL, ROMAN   0
76 // ITALIC        100
77 // OBLIQUE       110
78 const int FONT_SLANT_TYPE_TO_INT[] = { 0, 100, 110 };
79 const unsigned int NUM_FONT_SLANT_TYPE = sizeof( FONT_SLANT_TYPE_TO_INT ) / sizeof( int );
80
81 /**
82  * @brief Retrieves a table index for a given value.
83  *
84  * @param[in] value The value.
85  * @param[in] table The table.
86  * @param[in] maxIndex The maximum valid index of the table.
87  *
88  * @return The index to the closest available value
89  */
90 int ValueToIndex( int value, const int* const table, unsigned int maxIndex )
91 {
92   if( ( NULL == table ) ||
93       ( value <= table[0] ) )
94   {
95     return 0;
96   }
97
98   if( value >= table[maxIndex] )
99   {
100     return maxIndex;
101   }
102
103   for( unsigned int index = 0u; index < maxIndex; )
104   {
105     const unsigned int indexPlus = ++index;
106     const int v1 = table[index];
107     const int v2 = table[indexPlus];
108     if( ( v1 < value ) && ( value <= v2 ) )
109     {
110       return ( ( value - v1 ) < ( v2 - value ) ) ? index : indexPlus;
111     }
112
113     index = indexPlus;
114   }
115
116   return 0;
117 }
118
119 }
120
121 using Dali::Vector;
122
123 namespace Dali
124 {
125
126 namespace TextAbstraction
127 {
128
129 namespace Internal
130 {
131
132 /**
133  * @brief Returns the FontWidth's enum index for the given width value.
134  *
135  * @param[in] width The width value.
136  *
137  * @return The FontWidth's enum index.
138  */
139 FontWidth::Type IntToWidthType( int width )
140 {
141   return static_cast<FontWidth::Type>( ValueToIndex( width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u ) );
142 }
143
144 /**
145  * @brief Returns the FontWeight's enum index for the given weight value.
146  *
147  * @param[in] weight The weight value.
148  *
149  * @return The FontWeight's enum index.
150  */
151 FontWeight::Type IntToWeightType( int weight )
152 {
153   return static_cast<FontWeight::Type>( ValueToIndex( weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u ) );
154 }
155
156 /**
157  * @brief Returns the FontSlant's enum index for the given slant value.
158  *
159  * @param[in] slant The slant value.
160  *
161  * @return The FontSlant's enum index.
162  */
163 FontSlant::Type IntToSlantType( int slant )
164 {
165   return static_cast<FontSlant::Type>( ValueToIndex( slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u ) );
166 }
167
168 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
169                                                                         FontDescriptionId index )
170 : fontDescription( fontDescription ),
171   index( index )
172 {
173 }
174
175 FontClient::Plugin::FontIdCacheItem::FontIdCacheItem( FontDescriptionId validatedFontId,
176                                                       PointSize26Dot6 pointSize,
177                                                       FontId fontId )
178 : validatedFontId( validatedFontId ),
179   pointSize( pointSize ),
180   fontId( fontId )
181 {
182 }
183
184 FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
185                                           const FontPath& path,
186                                           PointSize26Dot6 pointSize,
187                                           FaceIndex face,
188                                           const FontMetrics& metrics )
189 : mFreeTypeFace( ftFace ),
190   mPath( path ),
191   mPointSize( pointSize ),
192   mFaceIndex( face ),
193   mMetrics( metrics ),
194   mFixedWidthPixels( 0.0f ),
195   mFixedHeightPixels( 0.0f ),
196   mIsFixedSizeBitmap( false )
197 {
198 }
199
200 FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
201                                           const FontPath& path,
202                                           PointSize26Dot6 pointSize,
203                                           FaceIndex face,
204                                           const FontMetrics& metrics,
205                                           float fixedWidth,
206                                           float fixedHeight )
207 : mFreeTypeFace( ftFace ),
208   mPath( path ),
209   mPointSize( pointSize ),
210   mFaceIndex( face ),
211   mMetrics( metrics ),
212   mFixedWidthPixels( fixedWidth ),
213   mFixedHeightPixels( fixedHeight ),
214   mIsFixedSizeBitmap( true )
215 {
216 }
217
218 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
219                             unsigned int verticalDpi )
220 : mFreeTypeLibrary( NULL ),
221   mDpiHorizontal( horizontalDpi ),
222   mDpiVertical( verticalDpi ),
223   mSystemFonts(),
224   mDefaultFonts(),
225   mFontCache(),
226   mValidatedFontCache(),
227   mFontDescriptionCache( 1u ),
228   mFontIdCache(),
229   mEllipsisCache()
230 {
231   int error = FT_Init_FreeType( &mFreeTypeLibrary );
232   if( FT_Err_Ok != error )
233   {
234     DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
235   }
236 }
237
238 FontClient::Plugin::~Plugin()
239 {
240   FT_Done_FreeType( mFreeTypeLibrary );
241 }
242
243 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
244                                  unsigned int verticalDpi )
245 {
246   mDpiHorizontal = horizontalDpi;
247   mDpiVertical = verticalDpi;
248 }
249
250 void FontClient::Plugin::SetDefaultFont( const FontDescription& fontDescription )
251 {
252   mDefaultFonts.clear();
253
254   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
255
256   FcResult result = FcResultMatch;
257
258   // Match the pattern.
259   FcFontSet* fontSet = FcFontSort( NULL /* use default configure */,
260                                    fontFamilyPattern,
261                                    false /* don't trim */,
262                                    NULL,
263                                    &result );
264
265   if( NULL != fontSet )
266   {
267     // Reserve some space to avoid reallocations.
268     mDefaultFonts.reserve( fontSet->nfont );
269
270     for( int i = 0u; i < fontSet->nfont; ++i )
271     {
272       FcPattern* fontPattern = fontSet->fonts[i];
273
274       FontPath path;
275
276       // Skip fonts with no path
277       if( GetFcString( fontPattern, FC_FILE, path ) )
278       {
279         mDefaultFonts.push_back( FontDescription() );
280         FontDescription& newFontDescription = mDefaultFonts.back();
281
282         newFontDescription.path = path;
283
284         int width = 0;
285         int weight = 0;
286         int slant = 0;
287         GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
288         GetFcInt( fontPattern, FC_WIDTH, width );
289         GetFcInt( fontPattern, FC_WEIGHT, weight );
290         GetFcInt( fontPattern, FC_SLANT, slant );
291         newFontDescription.width = IntToWidthType( width );
292         newFontDescription.weight = IntToWeightType( weight );
293         newFontDescription.slant = IntToSlantType( slant );
294       }
295     }
296
297     FcFontSetDestroy( fontSet );
298   }
299
300   FcPatternDestroy( fontFamilyPattern );
301 }
302
303 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
304 {
305   if( mDefaultFonts.empty() )
306   {
307     FontDescription fontDescription;
308     fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
309     fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
310     fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
311     fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
312     SetDefaultFont( fontDescription );
313   }
314
315   defaultFonts = mDefaultFonts;
316 }
317
318 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
319 {
320   if( mSystemFonts.empty() )
321   {
322     InitSystemFonts();
323   }
324
325   systemFonts = mSystemFonts;
326 }
327
328 void FontClient::Plugin::GetDescription( FontId id,
329                                          FontDescription& fontDescription ) const
330 {
331   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
332          endIt = mFontIdCache.end();
333        it != endIt;
334        ++it )
335   {
336     const FontIdCacheItem& item = *it;
337
338     if( item.fontId == id )
339     {
340       fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
341       return;
342     }
343   }
344
345   DALI_LOG_ERROR( "FontClient::Plugin::GetDescription. No description found for the font ID %d\n", id );
346 }
347
348 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
349 {
350   const FontId index = id - 1u;
351
352   if( id > 0u &&
353       index < mFontCache.size() )
354   {
355     return ( *( mFontCache.begin() + index ) ).mPointSize;
356   }
357   else
358   {
359     DALI_LOG_ERROR( "FontClient::Plugin::GetPointSize. Invalid font ID %d\n", id );
360   }
361
362   return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
363 }
364
365 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
366                                             PointSize26Dot6 requestedSize,
367                                             bool preferColor )
368 {
369   FontId fontId(0);
370   bool foundColor(false);
371
372   // Create the list of default fonts if it has not been created.
373   if( mDefaultFonts.empty() )
374   {
375     FontDescription fontDescription;
376     fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
377     fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
378     fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
379     fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
380     SetDefaultFont( fontDescription );
381   }
382
383   // Traverse the list of default fonts.
384   // Check for each default font if supports the character.
385
386   for( FontList::const_iterator it = mDefaultFonts.begin(), endIt = mDefaultFonts.end();
387        it != endIt;
388        ++it )
389   {
390     const FontDescription& description = *it;
391
392     FcPattern* pattern = CreateFontFamilyPattern( description );
393
394     FcResult result = FcResultMatch;
395     FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
396
397     FcCharSet* charSet = NULL;
398     FcPatternGetCharSet( match, FC_CHARSET, 0u, &charSet );
399
400     if( FcCharSetHasChar( charSet, charcode ) )
401     {
402       Vector< PointSize26Dot6 > fixedSizes;
403       GetFixedSizes( description,
404                      fixedSizes );
405
406       const Vector< PointSize26Dot6 >::SizeType count = fixedSizes.Count();
407       if( 0 != count )
408       {
409         // If the font is not scalable, pick the largest size <= requestedSize
410         PointSize26Dot6 size = fixedSizes[0];
411         for( unsigned int i=1; i<count; ++i )
412         {
413           if( fixedSizes[i] <= requestedSize &&
414               fixedSizes[i] > size )
415           {
416             size = fixedSizes[i];
417           }
418         }
419         requestedSize = size;
420       }
421
422       fontId = GetFontId( description,
423                           requestedSize,
424                           0u );
425
426       if( preferColor )
427       {
428         BufferImage bitmap = CreateBitmap( fontId, GetGlyphIndex(fontId,charcode) );
429         if( bitmap &&
430             Pixel::BGRA8888 == bitmap.GetPixelFormat() )
431         {
432           foundColor = true;
433         }
434       }
435
436       // Keep going unless we prefer a different (color) font
437       if( !preferColor || foundColor )
438       {
439         FcPatternDestroy( match );
440         FcPatternDestroy( pattern );
441         break;
442       }
443     }
444
445     FcPatternDestroy( match );
446     FcPatternDestroy( pattern );
447   }
448   return fontId;
449 }
450
451 FontId FontClient::Plugin::GetFontId( const FontPath& path,
452                                       PointSize26Dot6 pointSize,
453                                       FaceIndex faceIndex,
454                                       bool cacheDescription )
455 {
456   FontId id( 0 );
457
458   if( NULL != mFreeTypeLibrary )
459   {
460     FontId foundId(0);
461     if( FindFont( path, pointSize, faceIndex, foundId ) )
462     {
463       id = foundId;
464     }
465     else
466     {
467       id = CreateFont( path, pointSize, faceIndex, cacheDescription );
468     }
469   }
470
471   return id;
472 }
473
474 FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
475                                       PointSize26Dot6 pointSize,
476                                       FaceIndex faceIndex )
477 {
478   // This method uses three vectors which caches:
479   // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
480   // * The path to font file names.
481   // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
482
483   // 1) Checks in the cache if the font's description has been validated before.
484   //    If it was it gets an index to the vector with paths to font file names. Otherwise,
485   //    retrieves using font config a path to a font file name which matches with the
486   //    font's description. The path is stored in the chache.
487   //
488   // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
489   //    fon file names' exists. If exists, it gets the font id. If it doesn't it calls
490   //    the GetFontId() method with the path to the font file name and the point size to
491   //    get the font id.
492
493   // The font id to be returned.
494   FontId fontId = 0u;
495
496   // Check first if the font's description have been validated before.
497   FontDescriptionId validatedFontId = 0u;
498
499   if( !FindValidatedFont( fontDescription,
500                           validatedFontId ) )
501   {
502     // Use font config to validate the font's description.
503     ValidateFont( fontDescription,
504                   validatedFontId );
505   }
506
507   // Check if exists a pair 'validatedFontId, pointSize' in the cache.
508   if( !FindFont( validatedFontId, pointSize, fontId ) )
509   {
510     // Retrieve the font file name path.
511     const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
512
513     // Retrieve the font id. Do not cache the description as it has been already cached.
514     fontId = GetFontId( description.path,
515                         pointSize,
516                         faceIndex,
517                         false );
518
519     // Cache the pair 'validatedFontId, pointSize' to improve the following queries.
520     mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
521                                              pointSize,
522                                              fontId ) );
523   }
524
525   return fontId;
526 }
527
528 void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
529                                        FontDescriptionId& validatedFontId )
530 {
531   // Create a font pattern.
532   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
533
534   FcResult result = FcResultMatch;
535
536   // match the pattern
537   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
538
539   if( match )
540   {
541     // Get the path to the font file name.
542     int width = 0;
543     int weight = 0;
544     int slant = 0;
545     FontDescription description;
546     GetFcString( match, FC_FILE, description.path );
547     GetFcString( match, FC_FAMILY, description.family );
548     GetFcInt( match, FC_WIDTH, width );
549     GetFcInt( match, FC_WEIGHT, weight );
550     GetFcInt( match, FC_SLANT, slant );
551     description.width = IntToWidthType( width );
552     description.weight = IntToWeightType( weight );
553     description.slant = IntToSlantType( slant );
554
555     // Set the index to the vector of paths to font file names.
556     validatedFontId = mFontDescriptionCache.size();
557
558     // Add the path to the cache.
559     mFontDescriptionCache.push_back( description );
560
561     // Cache the index and the font's description.
562     FontDescriptionCacheItem item( description,
563                                    validatedFontId );
564
565     mValidatedFontCache.push_back( item );
566
567     // destroyed the matched pattern
568     FcPatternDestroy( match );
569   }
570   else
571   {
572     DALI_LOG_ERROR( "FontClient::Plugin::ValidateFont failed for font %s %d %d %d\n",
573                     fontDescription.family.c_str(),
574                     fontDescription.width,
575                     fontDescription.weight,
576                     fontDescription.slant );
577   }
578
579   // destroy the pattern
580   FcPatternDestroy( fontFamilyPattern );
581 }
582
583 void FontClient::Plugin::GetFontMetrics( FontId fontId,
584                                          FontMetrics& metrics,
585                                          int maxFixedSize )
586 {
587   if( fontId > 0 &&
588       fontId-1 < mFontCache.size() )
589   {
590     const CacheItem& font = mFontCache[fontId-1];
591
592     metrics = font.mMetrics;
593
594     // Adjust the metrics if the fixed-size font should be down-scaled
595     if( font.mIsFixedSizeBitmap &&
596         ( maxFixedSize > 0 ) &&
597         ( font.mFixedHeightPixels > maxFixedSize ) )
598     {
599       float scaleFactor = static_cast<float>(maxFixedSize) / static_cast<float>(font.mFixedHeightPixels);
600
601       metrics.ascender           *= scaleFactor;
602       metrics.descender          *= scaleFactor;
603       metrics.height             *= scaleFactor;
604       metrics.underlinePosition  *= scaleFactor;
605       metrics.underlineThickness *= scaleFactor;
606     }
607   }
608   else
609   {
610     DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
611   }
612 }
613
614 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
615                                               Character charcode )
616 {
617   GlyphIndex index( 0 );
618
619   if( fontId > 0 &&
620       fontId-1 < mFontCache.size() )
621   {
622     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
623
624     index = FT_Get_Char_Index( ftFace, charcode );
625   }
626
627   return index;
628 }
629
630 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
631                                           uint32_t size,
632                                           bool horizontal,
633                                           int maxFixedSize )
634 {
635   bool success( true );
636
637   for( unsigned int i=0; i<size; ++i )
638   {
639     FontId fontId = array[i].fontId;
640
641     if( fontId > 0 &&
642         fontId-1 < mFontCache.size() )
643     {
644       const CacheItem& font = mFontCache[fontId-1];
645
646       FT_Face ftFace = font.mFreeTypeFace;
647
648 #ifdef FREETYPE_BITMAP_SUPPORT
649       // Check to see if we should be loading a Fixed Size bitmap?
650       if ( font.mIsFixedSizeBitmap )
651       {
652         int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_COLOR );
653         if ( FT_Err_Ok == error )
654         {
655           array[i].width = font.mFixedWidthPixels;
656           array[i].height = font.mFixedHeightPixels;
657           array[i].advance = font.mFixedWidthPixels;
658           array[i].xBearing = 0.0f;
659           array[i].yBearing = font.mFixedHeightPixels;
660
661           // Adjust the metrics if the fixed-size font should be down-scaled
662           if( ( maxFixedSize > 0 ) &&
663               ( font.mFixedHeightPixels > maxFixedSize ) )
664           {
665             float scaleFactor = static_cast<float>(maxFixedSize) / static_cast<float>(font.mFixedHeightPixels);
666
667             array[i].width    *= scaleFactor;
668             array[i].height   *= scaleFactor;
669             array[i].advance  *= scaleFactor;
670             array[i].xBearing *= scaleFactor;
671             array[i].yBearing *= scaleFactor;
672
673             array[i].scaleFactor = scaleFactor;
674           }
675         }
676         else
677         {
678           DALI_LOG_ERROR( "FreeType Bitmap Load_Glyph error %d\n", error );
679           success = false;
680         }
681       }
682       else
683 #endif
684       {
685         int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
686
687         if( FT_Err_Ok == error )
688         {
689           array[i].width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
690           array[i].height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
691           if( horizontal )
692           {
693             array[i].xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
694             array[i].yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
695           }
696           else
697           {
698             array[i].xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
699             array[i].yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
700           }
701         }
702         else
703         {
704           success = false;
705         }
706       }
707     }
708     else
709     {
710       success = false;
711     }
712   }
713
714   return success;
715 }
716
717 BufferImage FontClient::Plugin::CreateBitmap( FontId fontId,
718                                               GlyphIndex glyphIndex )
719 {
720   BufferImage bitmap;
721
722   if( fontId > 0 &&
723       fontId-1 < mFontCache.size() )
724   {
725     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
726
727     FT_Error error;
728
729 #ifdef FREETYPE_BITMAP_SUPPORT
730     // Check to see if this is fixed size bitmap
731     if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
732     {
733       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
734     }
735     else
736 #endif
737     {
738       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
739     }
740     if( FT_Err_Ok == error )
741     {
742       FT_Glyph glyph;
743       error = FT_Get_Glyph( ftFace->glyph, &glyph );
744
745       // Convert to bitmap if necessary
746       if ( FT_Err_Ok == error )
747       {
748         if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
749         {
750           error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
751           if ( FT_Err_Ok == error )
752           {
753             FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
754             ConvertBitmap( bitmap, bitmapGlyph->bitmap );
755           }
756           else
757           {
758             DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
759           }
760         }
761         else
762         {
763           ConvertBitmap( bitmap, ftFace->glyph->bitmap );
764         }
765
766         // Created FT_Glyph object must be released with FT_Done_Glyph
767         FT_Done_Glyph( glyph );
768       }
769     }
770     else
771     {
772       DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
773     }
774   }
775
776   return bitmap;
777 }
778
779 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 pointSize )
780 {
781   // First look into the cache if there is an ellipsis glyph for the requested point size.
782   for( Vector<EllipsisItem>::ConstIterator it = mEllipsisCache.Begin(),
783          endIt = mEllipsisCache.End();
784        it != endIt;
785        ++it )
786   {
787     const EllipsisItem& item = *it;
788
789     if( fabsf( item.size - pointSize ) < Math::MACHINE_EPSILON_1000 )
790     {
791       // Use the glyph in the cache.
792       return item.glyph;
793     }
794   }
795
796   // No glyph has been found. Create one.
797   mEllipsisCache.PushBack( EllipsisItem() );
798   EllipsisItem& item = *( mEllipsisCache.End() - 1u );
799
800   item.size = pointSize;
801
802   // Find a font for the ellipsis glyph.
803   item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
804                                        pointSize,
805                                        false );
806
807   // Set the character index to access the glyph inside the font.
808   item.glyph.index = FT_Get_Char_Index( mFontCache[item.glyph.fontId-1].mFreeTypeFace,
809                                         ELLIPSIS_CHARACTER );
810
811   GetGlyphMetrics( &item.glyph, 1u, true, 0 );
812
813   return item.glyph;
814 }
815
816 void FontClient::Plugin::InitSystemFonts()
817 {
818   FcFontSet* fontSet = GetFcFontSet();
819
820   if( fontSet )
821   {
822     // Reserve some space to avoid reallocations.
823     mSystemFonts.reserve( fontSet->nfont );
824
825     for( int i = 0u; i < fontSet->nfont; ++i )
826     {
827       FcPattern* fontPattern = fontSet->fonts[i];
828
829       FontPath path;
830
831       // Skip fonts with no path
832       if( GetFcString( fontPattern, FC_FILE, path ) )
833       {
834         mSystemFonts.push_back( FontDescription() );
835         FontDescription& fontDescription = mSystemFonts.back();
836
837         fontDescription.path = path;
838
839         int width = 0;
840         int weight = 0;
841         int slant = 0;
842         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
843         GetFcInt( fontPattern, FC_WIDTH, width );
844         GetFcInt( fontPattern, FC_WEIGHT, weight );
845         GetFcInt( fontPattern, FC_SLANT, slant );
846         fontDescription.width = IntToWidthType( width );
847         fontDescription.weight = IntToWeightType( weight );
848         fontDescription.slant = IntToSlantType( slant );
849       }
850     }
851
852     FcFontSetDestroy( fontSet );
853   }
854 }
855
856 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription )
857 {
858   // create the cached font family lookup pattern
859   // a pattern holds a set of names, each name refers to a property of the font
860   FcPattern* fontFamilyPattern = FcPatternCreate();
861
862   // add a property to the pattern for the font family
863   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
864
865   FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, FONT_WIDTH_TYPE_TO_INT[fontDescription.width] );
866   FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight] );
867   FcPatternAddInteger( fontFamilyPattern, FC_SLANT, FONT_SLANT_TYPE_TO_INT[fontDescription.slant] );
868
869   // Add a property of the pattern, to say we want to match TrueType fonts
870   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
871
872   // modify the config, with the mFontFamilyPatterm
873   FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
874
875   // provide default values for unspecified properties in the font pattern
876   // e.g. patterns without a specified style or weight are set to Medium
877   FcDefaultSubstitute( fontFamilyPattern );
878
879   return fontFamilyPattern;
880 }
881
882 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
883 {
884   // create a new pattern.
885   // a pattern holds a set of names, each name refers to a property of the font
886   FcPattern* pattern = FcPatternCreate();
887
888   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
889   FcObjectSet* objectSet = FcObjectSetCreate();
890
891   // build an object set from a list of property names
892   FcObjectSetAdd( objectSet, FC_FILE );
893   FcObjectSetAdd( objectSet, FC_FAMILY );
894   FcObjectSetAdd( objectSet, FC_WIDTH );
895   FcObjectSetAdd( objectSet, FC_WEIGHT );
896   FcObjectSetAdd( objectSet, FC_SLANT );
897
898   // get a list of fonts
899   // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
900   FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
901
902   // clear up the object set
903   if( objectSet )
904   {
905     FcObjectSetDestroy( objectSet );
906   }
907   // clear up the pattern
908   if( pattern )
909   {
910     FcPatternDestroy( pattern );
911   }
912
913   return fontset;
914 }
915
916 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
917                                       const char* const n,
918                                       std::string& string )
919 {
920   FcChar8* file = NULL;
921   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
922
923   if( FcResultMatch == retVal )
924   {
925     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
926     string.assign( reinterpret_cast<const char*>( file ) );
927
928     return true;
929   }
930
931   return false;
932 }
933
934 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
935 {
936   const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
937
938   if( FcResultMatch == retVal )
939   {
940     return true;
941   }
942
943   return false;
944 }
945
946 FontId FontClient::Plugin::CreateFont( const FontPath& path,
947                                        PointSize26Dot6 pointSize,
948                                        FaceIndex faceIndex,
949                                        bool cacheDescription )
950 {
951   FontId id( 0 );
952
953   // Create & cache new font face
954   FT_Face ftFace;
955   int error = FT_New_Face( mFreeTypeLibrary,
956                            path.c_str(),
957                            0,
958                            &ftFace );
959
960   if( FT_Err_Ok == error )
961   {
962     // Check to see if the font contains fixed sizes?
963     if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
964     {
965       // Ensure this size is available
966       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
967       {
968         if ( static_cast<FT_Pos>(pointSize) == ftFace->available_sizes[ i ].size )
969         {
970           // Tell Freetype to use this size
971           error = FT_Select_Size( ftFace, i );
972           if ( FT_Err_Ok != error )
973           {
974             DALI_LOG_ERROR( "FreeType Select_Size error: %d\n", error );
975           }
976           else
977           {
978             float fixedWidth  = static_cast< float >( ftFace->available_sizes[ i ].width );
979             float fixedHeight = static_cast< float >( ftFace->available_sizes[ i ].height );
980
981             // Indicate that the font is a fixed sized bitmap
982             FontMetrics metrics( fixedHeight, // The ascender in pixels.
983                                  0.0f,
984                                  fixedHeight, // The height in pixels.
985                                  0.0f,
986                                  0.0f );
987
988             mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics, fixedWidth, fixedHeight ) );
989             id = mFontCache.size();
990
991             if( cacheDescription )
992             {
993               FontDescription description;
994               description.path = path;
995               description.family = FontFamily( ftFace->family_name );
996
997               // Note FreeType doesn't give too much info to build a proper font style.
998               if( ftFace->style_flags | FT_STYLE_FLAG_ITALIC )
999               {
1000                 description.slant = FontSlant::ITALIC;
1001               }
1002               if( ftFace->style_flags | FT_STYLE_FLAG_BOLD )
1003               {
1004                 description.weight = FontWeight::BOLD;
1005               }
1006
1007               mFontDescriptionCache.push_back( description );
1008             }
1009             return id;
1010           }
1011         }
1012       }
1013
1014       // Can't find this size
1015       std::stringstream sizes;
1016       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1017       {
1018         if ( i )
1019         {
1020           sizes << ", ";
1021         }
1022         sizes << ftFace->available_sizes[ i ].size;
1023       }
1024       DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n",
1025                        path.c_str(), pointSize, sizes.str().c_str() );
1026     }
1027     else
1028     {
1029       error = FT_Set_Char_Size( ftFace,
1030                               0,
1031                               pointSize,
1032                               mDpiHorizontal,
1033                               mDpiVertical );
1034
1035       if( FT_Err_Ok == error )
1036       {
1037
1038         FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1039
1040         FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
1041                              static_cast< float >( ftMetrics.descender ) * FROM_266,
1042                              static_cast< float >( ftMetrics.height    ) * FROM_266,
1043                              static_cast< float >( ftFace->underline_position ) * FROM_266,
1044                              static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1045
1046         mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics ) );
1047         id = mFontCache.size();
1048
1049         if( cacheDescription )
1050         {
1051           FontDescription description;
1052           description.path = path;
1053           description.family = FontFamily( ftFace->family_name );
1054
1055           // Note FreeType doesn't give too much info to build a proper font style.
1056           if( ftFace->style_flags | FT_STYLE_FLAG_ITALIC )
1057           {
1058             description.slant = FontSlant::ITALIC;
1059           }
1060           if( ftFace->style_flags | FT_STYLE_FLAG_BOLD )
1061           {
1062             description.weight = FontWeight::BOLD;
1063           }
1064
1065           mFontDescriptionCache.push_back( description );
1066         }
1067       }
1068       else
1069       {
1070         DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, pointSize );
1071       }
1072     }
1073   }
1074   else
1075   {
1076     DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
1077   }
1078
1079   return id;
1080 }
1081
1082 void FontClient::Plugin::ConvertBitmap( BufferImage& destBitmap,
1083                                         FT_Bitmap srcBitmap )
1084 {
1085   if( srcBitmap.width*srcBitmap.rows > 0 )
1086   {
1087     switch( srcBitmap.pixel_mode )
1088     {
1089       case FT_PIXEL_MODE_GRAY:
1090       {
1091         if( srcBitmap.pitch == static_cast< int >( srcBitmap.width ) )
1092         {
1093           destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
1094
1095           PixelBuffer* destBuffer = destBitmap.GetBuffer();
1096           if( destBuffer )
1097           {
1098             memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
1099           }
1100           else
1101           {
1102             DALI_LOG_ERROR( "GetBuffer returns null\n" );
1103           }
1104         }
1105         break;
1106       }
1107
1108 #ifdef FREETYPE_BITMAP_SUPPORT
1109       case FT_PIXEL_MODE_BGRA:
1110       {
1111         if ( srcBitmap.pitch == static_cast< int >( srcBitmap.width << 2 ) )
1112         {
1113           destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::BGRA8888 );
1114
1115           PixelBuffer* destBuffer = destBitmap.GetBuffer();
1116           if( destBuffer )
1117           {
1118             memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows*4 );
1119           }
1120           else
1121           {
1122             DALI_LOG_ERROR( "GetBuffer returns null\n" );
1123           }
1124         }
1125         break;
1126       }
1127 #endif
1128       default:
1129       {
1130         DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" );
1131         break;
1132       }
1133     }
1134   }
1135 }
1136
1137 bool FontClient::Plugin::FindFont( const FontPath& path,
1138                                    PointSize26Dot6 pointSize,
1139                                    FaceIndex faceIndex,
1140                                    FontId& fontId ) const
1141 {
1142   fontId = 0u;
1143   for( std::vector<CacheItem>::const_iterator it = mFontCache.begin(),
1144          endIt = mFontCache.end();
1145        it != endIt;
1146        ++it, ++fontId )
1147   {
1148     const CacheItem& cacheItem = *it;
1149
1150     if( cacheItem.mPointSize == pointSize &&
1151         cacheItem.mFaceIndex == faceIndex &&
1152         cacheItem.mPath == path )
1153     {
1154       ++fontId;
1155       return true;
1156     }
1157   }
1158
1159   return false;
1160 }
1161
1162 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1163                                             FontDescriptionId& validatedFontId )
1164 {
1165   validatedFontId = 0u;
1166
1167   for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
1168          endIt = mValidatedFontCache.end();
1169        it != endIt;
1170        ++it )
1171   {
1172     const FontDescriptionCacheItem& item = *it;
1173
1174     if( !fontDescription.family.empty() &&
1175         ( fontDescription.family == item.fontDescription.family ) &&
1176         ( fontDescription.width == item.fontDescription.width ) &&
1177         ( fontDescription.weight == item.fontDescription.weight ) &&
1178         ( fontDescription.slant == item.fontDescription.slant ) )
1179     {
1180       validatedFontId = item.index;
1181
1182       return true;
1183     }
1184   }
1185
1186   return false;
1187 }
1188
1189 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1190                                    PointSize26Dot6 pointSize,
1191                                    FontId& fontId )
1192 {
1193   fontId = 0u;
1194
1195   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
1196          endIt = mFontIdCache.end();
1197        it != endIt;
1198        ++it )
1199   {
1200     const FontIdCacheItem& item = *it;
1201
1202     if( ( validatedFontId == item.validatedFontId ) &&
1203         ( pointSize == item.pointSize ) )
1204     {
1205       fontId = item.fontId;
1206       return true;
1207     }
1208   }
1209
1210   return false;
1211 }
1212
1213 bool FontClient::Plugin::IsScalable( const FontPath& path )
1214 {
1215   FT_Face ftFace;
1216   int error = FT_New_Face( mFreeTypeLibrary,
1217                            path.c_str(),
1218                            0,
1219                            &ftFace );
1220   if( FT_Err_Ok != error )
1221   {
1222     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1223   }
1224   return ( ftFace->num_fixed_sizes == 0 );
1225 }
1226
1227 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1228 {
1229   // Create a font pattern.
1230   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1231
1232   FcResult result = FcResultMatch;
1233
1234   // match the pattern
1235   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1236   bool isScalable = true;
1237
1238   if( match )
1239   {
1240     // Get the path to the font file name.
1241     FontPath path;
1242     GetFcString( match, FC_FILE, path );
1243     isScalable = IsScalable( path );
1244   }
1245   else
1246   {
1247     DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1248                     fontDescription.family.c_str(),
1249                     fontDescription.width,
1250                     fontDescription.weight,
1251                     fontDescription.slant );
1252   }
1253   FcPatternDestroy( fontFamilyPattern );
1254   FcPatternDestroy( match );
1255   return isScalable;
1256 }
1257
1258 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1259 {
1260   // Empty the caller container
1261   sizes.Clear();
1262
1263   FT_Face ftFace;
1264   int error = FT_New_Face( mFreeTypeLibrary,
1265                            path.c_str(),
1266                            0,
1267                            &ftFace );
1268   if( FT_Err_Ok != error )
1269   {
1270     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1271   }
1272
1273   // Fetch the number of fixed sizes available
1274   if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1275   {
1276     for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1277     {
1278       sizes.PushBack( ftFace->available_sizes[ i ].size );
1279     }
1280   }
1281 }
1282
1283 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1284                                         Vector< PointSize26Dot6 >& sizes )
1285 {
1286   // Create a font pattern.
1287   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1288
1289   FcResult result = FcResultMatch;
1290
1291   // match the pattern
1292   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1293
1294   if( match )
1295   {
1296     // Get the path to the font file name.
1297     FontPath path;
1298     GetFcString( match, FC_FILE, path );
1299     GetFixedSizes( path, sizes );
1300   }
1301   else
1302   {
1303     DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1304                     fontDescription.family.c_str(),
1305                     fontDescription.width,
1306                     fontDescription.weight,
1307                     fontDescription.slant );
1308   }
1309   FcPatternDestroy( match );
1310   FcPatternDestroy( fontFamilyPattern );
1311 }
1312
1313 } // namespace Internal
1314
1315 } // namespace TextAbstraction
1316
1317 } // namespace Dali