Fix compilation error with older versions of freetype where width and rows are int...
[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 #include <dali/integration-api/platform-abstraction.h>
27 #include <dali/internal/text-abstraction/font-client-helper.h>
28 #include <adaptor-impl.h>
29
30 // EXTERNAL INCLUDES
31 #include <fontconfig/fontconfig.h>
32
33 namespace
34 {
35
36 #if defined(DEBUG_ENABLED)
37 Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
38 #endif
39
40 /**
41  * Conversion from Fractional26.6 to float
42  */
43 const float FROM_266 = 1.0f / 64.0f;
44 const float POINTS_PER_INCH = 72.f;
45
46 const std::string FONT_FORMAT( "TrueType" );
47 const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
48 const int DEFAULT_FONT_WIDTH  = 100; // normal
49 const int DEFAULT_FONT_WEIGHT =  80; // normal
50 const int DEFAULT_FONT_SLANT  =   0; // normal
51
52 const uint32_t ELLIPSIS_CHARACTER = 0x2026;
53
54 const bool FONT_FIXED_SIZE_BITMAP( true );
55
56 // http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
57
58 // NONE            -1  --> DEFAULT_FONT_WIDTH (NORMAL) will be used.
59 // ULTRA_CONDENSED 50
60 // EXTRA_CONDENSED 63
61 // CONDENSED       75
62 // SEMI_CONDENSED  87
63 // NORMAL         100
64 // SEMI_EXPANDED  113
65 // EXPANDED       125
66 // EXTRA_EXPANDED 150
67 // ULTRA_EXPANDED 200
68 const int FONT_WIDTH_TYPE_TO_INT[] = { -1, 50, 63, 75, 87, 100, 113, 125, 150, 200 };
69 const unsigned int NUM_FONT_WIDTH_TYPE = sizeof( FONT_WIDTH_TYPE_TO_INT ) / sizeof( int );
70
71 // NONE                       -1  --> DEFAULT_FONT_WEIGHT (NORMAL) will be used.
72 // THIN                        0
73 // ULTRA_LIGHT, EXTRA_LIGHT   40
74 // LIGHT                      50
75 // DEMI_LIGHT, SEMI_LIGHT     55
76 // BOOK                       75
77 // NORMAL, REGULAR            80
78 // MEDIUM                    100
79 // DEMI_BOLD, SEMI_BOLD      180
80 // BOLD                      200
81 // ULTRA_BOLD, EXTRA_BOLD    205
82 // BLACK, HEAVY, EXTRA_BLACK 210
83 const int FONT_WEIGHT_TYPE_TO_INT[] = { -1, 0, 40, 50, 55, 75, 80, 100, 180, 200, 205, 210 };
84 const unsigned int NUM_FONT_WEIGHT_TYPE = sizeof( FONT_WEIGHT_TYPE_TO_INT ) / sizeof( int );
85
86 // NONE             -1 --> DEFAULT_FONT_SLANT (NORMAL) will be used.
87 // NORMAL, ROMAN     0
88 // ITALIC          100
89 // OBLIQUE         110
90 const int FONT_SLANT_TYPE_TO_INT[] = { -1, 0, 100, 110 };
91 const unsigned int NUM_FONT_SLANT_TYPE = sizeof( FONT_SLANT_TYPE_TO_INT ) / sizeof( int );
92
93 } // namespace
94
95 using Dali::Vector;
96
97 namespace Dali
98 {
99
100 namespace TextAbstraction
101 {
102
103 namespace Internal
104 {
105
106 /**
107  * @brief Returns the FontWidth's enum index for the given width value.
108  *
109  * @param[in] width The width value.
110  *
111  * @return The FontWidth's enum index.
112  */
113 FontWidth::Type IntToWidthType( int width )
114 {
115   return static_cast<FontWidth::Type>( ValueToIndex( width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u ) );
116 }
117
118 /**
119  * @brief Returns the FontWeight's enum index for the given weight value.
120  *
121  * @param[in] weight The weight value.
122  *
123  * @return The FontWeight's enum index.
124  */
125 FontWeight::Type IntToWeightType( int weight )
126 {
127   return static_cast<FontWeight::Type>( ValueToIndex( weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u ) );
128 }
129
130 /**
131  * @brief Returns the FontSlant's enum index for the given slant value.
132  *
133  * @param[in] slant The slant value.
134  *
135  * @return The FontSlant's enum index.
136  */
137 FontSlant::Type IntToSlantType( int slant )
138 {
139   return static_cast<FontSlant::Type>( ValueToIndex( slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u ) );
140 }
141
142 FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( const FontDescription& font, FontList* list )
143 : fontDescription( font ),
144   fallbackFonts( list )
145 {
146 }
147
148 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
149                                                                         FontDescriptionId index )
150 : fontDescription( fontDescription ),
151   index( index )
152 {
153 }
154
155 FontClient::Plugin::FontIdCacheItem::FontIdCacheItem( FontDescriptionId validatedFontId,
156                                                       PointSize26Dot6 requestedPointSize,
157                                                       FontId fontId )
158 : validatedFontId( validatedFontId ),
159   requestedPointSize( requestedPointSize ),
160   fontId( fontId )
161 {
162 }
163
164 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
165                                                           const FontPath& path,
166                                                           PointSize26Dot6 requestedPointSize,
167                                                           FaceIndex face,
168                                                           const FontMetrics& metrics )
169 : mFreeTypeFace( ftFace ),
170   mPath( path ),
171   mRequestedPointSize( requestedPointSize ),
172   mFaceIndex( face ),
173   mMetrics( metrics ),
174   mFixedWidthPixels( 0.0f ),
175   mFixedHeightPixels( 0.0f ),
176   mVectorFontId( 0 ),
177   mIsFixedSizeBitmap( false )
178 {
179 }
180
181 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
182                                                           const FontPath& path,
183                                                           PointSize26Dot6 requestedPointSize,
184                                                           FaceIndex face,
185                                                           const FontMetrics& metrics,
186                                                           float fixedWidth,
187                                                           float fixedHeight )
188 : mFreeTypeFace( ftFace ),
189   mPath( path ),
190   mRequestedPointSize( requestedPointSize ),
191   mFaceIndex( face ),
192   mMetrics( metrics ),
193   mFixedWidthPixels( fixedWidth ),
194   mFixedHeightPixels( fixedHeight ),
195   mVectorFontId( 0 ),
196   mIsFixedSizeBitmap( true )
197 {
198 }
199
200 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
201                             unsigned int verticalDpi )
202 : mFreeTypeLibrary( NULL ),
203   mDpiHorizontal( horizontalDpi ),
204   mDpiVertical( verticalDpi ),
205   mDefaultFontDescription(),
206   mSystemFonts(),
207   mDefaultFonts(),
208   mFontCache(),
209   mValidatedFontCache(),
210   mFontDescriptionCache( 1u ),
211   mFontIdCache(),
212   mVectorFontCache( NULL ),
213   mEllipsisCache(),
214   mDefaultFontDescriptionCached( false )
215 {
216   int error = FT_Init_FreeType( &mFreeTypeLibrary );
217   if( FT_Err_Ok != error )
218   {
219     DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
220   }
221
222 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
223   mVectorFontCache = new VectorFontCache( mFreeTypeLibrary );
224 #endif
225 }
226
227 FontClient::Plugin::~Plugin()
228 {
229   for( std::vector<FallbackCacheItem>::iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
230        it != endIt;
231        ++it )
232   {
233     FallbackCacheItem& item = *it;
234
235     if( item.fallbackFonts )
236     {
237       delete item.fallbackFonts;
238       item.fallbackFonts = NULL;
239     }
240   }
241
242 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
243   delete mVectorFontCache;
244 #endif
245
246   FT_Done_FreeType( mFreeTypeLibrary );
247 }
248
249 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
250                                  unsigned int verticalDpi )
251 {
252   mDpiHorizontal = horizontalDpi;
253   mDpiVertical = verticalDpi;
254 }
255
256 void FontClient::Plugin::ResetSystemDefaults()
257 {
258   mDefaultFontDescriptionCached = false;
259 }
260
261 void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList )
262 {
263   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::SetFontList family(%s)\n", fontDescription.family.c_str() );
264
265   fontList.clear();
266
267   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
268
269   FcResult result = FcResultMatch;
270
271   // Match the pattern.
272   FcFontSet* fontSet = FcFontSort( NULL /* use default configure */,
273                                    fontFamilyPattern,
274                                    false /* don't trim */,
275                                    NULL,
276                                    &result );
277
278   if( NULL != fontSet )
279   {
280     // Reserve some space to avoid reallocations.
281     fontList.reserve( fontSet->nfont );
282
283     for( int i = 0u; i < fontSet->nfont; ++i )
284     {
285       FcPattern* fontPattern = fontSet->fonts[i];
286
287       FontPath path;
288
289       // Skip fonts with no path
290       if( GetFcString( fontPattern, FC_FILE, path ) )
291       {
292         fontList.push_back( FontDescription() );
293         FontDescription& newFontDescription = fontList.back();
294
295         newFontDescription.path = path;
296
297         int width = 0;
298         int weight = 0;
299         int slant = 0;
300         GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
301         GetFcInt( fontPattern, FC_WIDTH, width );
302         GetFcInt( fontPattern, FC_WEIGHT, weight );
303         GetFcInt( fontPattern, FC_SLANT, slant );
304         newFontDescription.width = IntToWidthType( width );
305         newFontDescription.weight = IntToWeightType( weight );
306         newFontDescription.slant = IntToSlantType( slant );
307       }
308     }
309
310     FcFontSetDestroy( fontSet );
311   }
312
313   FcPatternDestroy( fontFamilyPattern );
314 }
315
316 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
317 {
318   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultFonts mDefaultFonts(%s)\n", ( mDefaultFonts.empty()?"empty":"valid" ) );
319
320   if( mDefaultFonts.empty() )
321   {
322     FontDescription fontDescription;
323     fontDescription.family = DEFAULT_FONT_FAMILY_NAME;  // todo This could be set to the Platform font
324     fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
325     fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
326     fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
327     SetFontList( fontDescription, mDefaultFonts );
328   }
329
330   defaultFonts = mDefaultFonts;
331 }
332
333 void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
334 {
335   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultPlatformFontDescription\n");
336
337   if( !mDefaultFontDescriptionCached )
338   {
339     FcInitReinitialize(); // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
340
341     FcPattern* matchPattern = FcPatternCreate();
342     FcConfigSubstitute(NULL, matchPattern, FcMatchPattern);
343     FcDefaultSubstitute( matchPattern );
344
345     MatchFontDescriptionToPattern( matchPattern, mDefaultFontDescription );
346     FcPatternDestroy( matchPattern );
347
348     mDefaultFontDescriptionCached = true;
349   }
350
351   fontDescription.path   = mDefaultFontDescription.path;
352   fontDescription.family = mDefaultFontDescription.family;
353   fontDescription.width  = mDefaultFontDescription.width;
354   fontDescription.weight = mDefaultFontDescription.weight;
355   fontDescription.slant  = mDefaultFontDescription.slant;
356 }
357
358 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
359 {
360   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetSystemFonts\n");
361
362   if( mSystemFonts.empty() )
363   {
364     InitSystemFonts();
365   }
366
367   systemFonts = mSystemFonts;
368 }
369
370 void FontClient::Plugin::GetDescription( FontId id,
371                                          FontDescription& fontDescription ) const
372 {
373   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
374          endIt = mFontIdCache.end();
375        it != endIt;
376        ++it )
377   {
378     const FontIdCacheItem& item = *it;
379
380     if( item.fontId == id )
381     {
382       fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
383       return;
384     }
385   }
386
387   DALI_LOG_ERROR( "FontClient::Plugin::GetDescription. No description found for the font ID %d\n", id );
388 }
389
390 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
391 {
392   const FontId index = id - 1u;
393
394   if( id > 0u &&
395       index < mFontCache.size() )
396   {
397     return ( *( mFontCache.begin() + index ) ).mRequestedPointSize;
398   }
399   else
400   {
401     DALI_LOG_ERROR( "FontClient::Plugin::GetPointSize. Invalid font ID %d\n", id );
402   }
403
404   return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
405 }
406
407 FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList,
408                                                  Character charcode,
409                                                  PointSize26Dot6 requestedPointSize,
410                                                  bool preferColor )
411 {
412   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFontForCharacter\n");
413
414   FontId fontId = 0u;
415   bool foundColor = false;
416
417   // Traverse the list of fonts.
418   // Check for each font if supports the character.
419   for( FontList::const_iterator it = fontList.begin(), endIt = fontList.end();
420        it != endIt;
421        ++it )
422   {
423     const FontDescription& description = *it;
424
425     FcPattern* pattern = CreateFontFamilyPattern( description );
426
427     FcResult result = FcResultMatch;
428     FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
429
430     FcCharSet* charSet = NULL;
431     FcPatternGetCharSet( match, FC_CHARSET, 0u, &charSet );
432
433     if( FcCharSetHasChar( charSet, charcode ) )
434     {
435       Vector< PointSize26Dot6 > fixedSizes;
436       GetFixedSizes( description,
437                      fixedSizes );
438
439       PointSize26Dot6 actualPointSize = requestedPointSize;
440
441       const Vector< PointSize26Dot6 >::SizeType count = fixedSizes.Count();
442
443       if( 0 != count )
444       {
445         // If the font is not scalable, pick the largest size <= requestedPointSize
446         actualPointSize = fixedSizes[0];
447         for( unsigned int i=1; i<count; ++i )
448         {
449           if( fixedSizes[i] <= requestedPointSize &&
450               fixedSizes[i] > actualPointSize )
451           {
452             actualPointSize = fixedSizes[i];
453           }
454         }
455       }
456
457       fontId = GetFontId( description,
458                           requestedPointSize,
459                           actualPointSize,
460                           0u );
461
462       if( preferColor )
463       {
464         foundColor = IsColorGlyph( fontId, GetGlyphIndex( fontId, charcode ) );
465       }
466
467       // Keep going unless we prefer a different (color) font.
468       if( !preferColor || foundColor )
469       {
470         FcPatternDestroy( match );
471         FcPatternDestroy( pattern );
472         break;
473       }
474     }
475
476     FcPatternDestroy( match );
477     FcPatternDestroy( pattern );
478   }
479
480   return fontId;
481 }
482
483 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
484                                             PointSize26Dot6 requestedPointSize,
485                                             bool preferColor )
486 {
487   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindDefaultFont DefaultFontsList(%s)\n", (mDefaultFonts.empty()?"empty":"created") );
488
489   FontId fontId(0);
490
491   // Create the list of default fonts if it has not been created.
492   if( mDefaultFonts.empty() )
493   {
494     FontDescription fontDescription;
495     fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
496     fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
497     fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
498     fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
499
500     SetFontList( fontDescription, mDefaultFonts );
501   }
502
503   // Traverse the list of default fonts.
504   // Check for each default font if supports the character.
505   fontId = FindFontForCharacter( mDefaultFonts, charcode, requestedPointSize, preferColor );
506
507   return fontId;
508 }
509
510 FontId FontClient::Plugin::FindFallbackFont( Character charcode,
511                                              const FontDescription& preferredFontDescription,
512                                              PointSize26Dot6 requestedPointSize,
513                                              bool preferColor )
514 {
515   // The font id to be returned.
516   FontId fontId = 0u;
517
518   FontDescription fontDescription;
519
520   // Fill the font description with the preferred font description and complete with the defaults.
521   fontDescription.family = preferredFontDescription.family.empty() ? DEFAULT_FONT_FAMILY_NAME : preferredFontDescription.family;
522   fontDescription.weight = ( ( FontWeight::NONE == preferredFontDescription.weight ) ? IntToWeightType( DEFAULT_FONT_WEIGHT ) : preferredFontDescription.weight );
523   fontDescription.width = ( ( FontWidth::NONE == preferredFontDescription.width ) ? IntToWidthType( DEFAULT_FONT_WIDTH ) : preferredFontDescription.width );
524   fontDescription.slant = ( ( FontSlant::NONE == preferredFontDescription.slant ) ? IntToSlantType( DEFAULT_FONT_SLANT ) : preferredFontDescription.slant );
525
526   // Check first if the font's description has been queried before.
527   FontList* fontList( NULL );
528
529   if( !FindFallbackFontList( fontDescription, fontList ) )
530   {
531     fontList = new FontList;
532     SetFontList( fontDescription, *fontList );
533
534     // Add the font-list to the cache.
535     mFallbackCache.push_back( FallbackCacheItem( fontDescription, fontList ) );
536   }
537
538   if( fontList )
539   {
540     fontId = FindFontForCharacter( *fontList, charcode, requestedPointSize, preferColor );
541   }
542
543   return fontId;
544 }
545
546 FontId FontClient::Plugin::GetFontId( const FontPath& path,
547                                       PointSize26Dot6 requestedPointSize,
548                                       PointSize26Dot6 actualPointSize,
549                                       FaceIndex faceIndex,
550                                       bool cacheDescription )
551 {
552   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId fontPatch:%s\n", path.c_str() );
553
554   FontId id( 0 );
555
556   if( NULL != mFreeTypeLibrary )
557   {
558     FontId foundId(0);
559     if( FindFont( path, requestedPointSize, faceIndex, foundId ) )
560     {
561       id = foundId;
562     }
563     else
564     {
565       id = CreateFont( path, requestedPointSize, actualPointSize, faceIndex, cacheDescription );
566     }
567   }
568
569   return id;
570 }
571
572 FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
573                                       PointSize26Dot6 requestedPointSize,
574                                       PointSize26Dot6 actualPointSize,
575                                       FaceIndex faceIndex )
576 {
577   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId font family(%s)\n", fontDescription.family.c_str() );
578
579   // This method uses three vectors which caches:
580   // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
581   // * The path to font file names.
582   // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
583
584   // 1) Checks in the cache if the font's description has been validated before.
585   //    If it was it gets an index to the vector with paths to font file names. Otherwise,
586   //    retrieves using font config a path to a font file name which matches with the
587   //    font's description. The path is stored in the cache.
588   //
589   // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
590   //    font file names' exists. If exists, it gets the font id. If it doesn't it calls
591   //    the GetFontId() method with the path to the font file name and the point size to
592   //    get the font id.
593
594   // The font id to be returned.
595   FontId fontId = 0u;
596
597   // Check first if the font's description have been validated before.
598   FontDescriptionId validatedFontId = 0u;
599
600   if( !FindValidatedFont( fontDescription,
601                           validatedFontId ) )
602   {
603     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId Validating Font\n");
604
605     // Use font config to validate the font's description.
606     ValidateFont( fontDescription,
607                   validatedFontId );
608   }
609
610   // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
611   if( !FindFont( validatedFontId, requestedPointSize, fontId ) )
612   {
613     // Retrieve the font file name path.
614     const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
615
616     // Retrieve the font id. Do not cache the description as it has been already cached.
617     fontId = GetFontId( description.path,
618                         requestedPointSize,
619                         actualPointSize,
620                         faceIndex,
621                         false );
622
623     // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
624     mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
625                                              requestedPointSize,
626                                              fontId ) );
627   }
628
629   return fontId;
630 }
631
632 void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
633                                        FontDescriptionId& validatedFontId )
634 {
635   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValidateFont Validating Font family(%s) \n", fontDescription.family.c_str() );
636
637   // Create a font pattern.
638   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
639
640   FontDescription description;
641
642   bool matched = MatchFontDescriptionToPattern( fontFamilyPattern, description );
643   FcPatternDestroy( fontFamilyPattern );
644
645   if( matched )
646   {
647     // Set the index to the vector of paths to font file names.
648     validatedFontId = mFontDescriptionCache.size();
649
650     // Add the path to the cache.
651     mFontDescriptionCache.push_back( description );
652
653     // Cache the index and the matched font's description.
654     FontDescriptionCacheItem item( description,
655                                    validatedFontId );
656
657     mValidatedFontCache.push_back( item );
658
659     if( ( fontDescription.family != description.family ) ||
660         ( fontDescription.width != description.width )   ||
661         ( fontDescription.weight != description.weight ) ||
662         ( fontDescription.slant != description.slant ) )
663     {
664       // Cache the given font's description if it's different than the matched.
665       FontDescriptionCacheItem item( fontDescription,
666                                      validatedFontId );
667
668       mValidatedFontCache.push_back( item );
669     }
670   }
671   else
672   {
673     DALI_LOG_ERROR( "FontClient::Plugin::ValidateFont failed for font %s %d %d %d\n",
674                     fontDescription.family.c_str(),
675                     fontDescription.width,
676                     fontDescription.weight,
677                     fontDescription.slant );
678   }
679
680   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValidateFont validatedFontId(%u) font family(%s)\n", validatedFontId, fontDescription.family.c_str() );
681 }
682
683 void FontClient::Plugin::GetFontMetrics( FontId fontId,
684                                          FontMetrics& metrics )
685 {
686   if( ( fontId > 0 ) &&
687       ( fontId - 1u < mFontCache.size() ) )
688   {
689     const FontFaceCacheItem& font = mFontCache[fontId-1];
690
691     metrics = font.mMetrics;
692
693     // Adjust the metrics if the fixed-size font should be down-scaled
694     if( font.mIsFixedSizeBitmap )
695     {
696       const float desiredFixedSize =  static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
697
698       if( desiredFixedSize > 0.f )
699       {
700         const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
701
702         metrics.ascender = floorf( metrics.ascender * scaleFactor );
703         metrics.descender = floorf( metrics.descender * scaleFactor );
704         metrics.height = floorf( metrics.height * scaleFactor );
705         metrics.underlinePosition = floorf( metrics.underlinePosition * scaleFactor );
706         metrics.underlineThickness = floorf( metrics.underlineThickness * scaleFactor );
707       }
708     }
709   }
710   else
711   {
712     DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
713   }
714 }
715
716 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
717                                               Character charcode )
718 {
719   GlyphIndex index( 0 );
720
721   if( fontId > 0 &&
722       fontId-1 < mFontCache.size() )
723   {
724     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
725
726     index = FT_Get_Char_Index( ftFace, charcode );
727   }
728
729   return index;
730 }
731
732 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
733                                           uint32_t size,
734                                           GlyphType type,
735                                           bool horizontal )
736 {
737   if( VECTOR_GLYPH == type )
738   {
739     return GetVectorMetrics( array, size, horizontal );
740   }
741
742   return GetBitmapMetrics( array, size, horizontal );
743 }
744
745 bool FontClient::Plugin::GetBitmapMetrics( GlyphInfo* array,
746                                            uint32_t size,
747                                            bool horizontal )
748 {
749   bool success( true );
750
751   for( unsigned int i=0; i<size; ++i )
752   {
753     GlyphInfo& glyph = array[i];
754
755     FontId fontId = glyph.fontId;
756
757     if( fontId > 0 &&
758         fontId-1 < mFontCache.size() )
759     {
760       const FontFaceCacheItem& font = mFontCache[fontId-1];
761
762       FT_Face ftFace = font.mFreeTypeFace;
763
764 #ifdef FREETYPE_BITMAP_SUPPORT
765       // Check to see if we should be loading a Fixed Size bitmap?
766       if ( font.mIsFixedSizeBitmap )
767       {
768         int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_COLOR );
769         if ( FT_Err_Ok == error )
770         {
771           glyph.width = font.mFixedWidthPixels;
772           glyph.height = font.mFixedHeightPixels;
773           glyph.advance = font.mFixedWidthPixels;
774           glyph.xBearing = 0.0f;
775           glyph.yBearing = font.mFixedHeightPixels;
776
777           // Adjust the metrics if the fixed-size font should be down-scaled
778           const float desiredFixedSize =  static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
779
780           if( desiredFixedSize > 0.f )
781           {
782             const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
783
784             glyph.width = floorf( glyph.width * scaleFactor );
785             glyph.height = floorf( glyph.height * scaleFactor );
786             glyph.advance = floorf( glyph.advance * scaleFactor );
787             glyph.xBearing = floorf( glyph.xBearing * scaleFactor );
788             glyph.yBearing = floorf( glyph.yBearing * scaleFactor );
789
790             glyph.scaleFactor = scaleFactor;
791           }
792         }
793         else
794         {
795           DALI_LOG_ERROR( "FreeType Bitmap Load_Glyph error %d\n", error );
796           success = false;
797         }
798       }
799       else
800 #endif
801       {
802         int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_DEFAULT );
803
804         if( FT_Err_Ok == error )
805         {
806           glyph.width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
807           glyph.height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
808           if( horizontal )
809           {
810             glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
811             glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
812           }
813           else
814           {
815             glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
816             glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
817           }
818         }
819         else
820         {
821           success = false;
822         }
823       }
824     }
825     else
826     {
827       success = false;
828     }
829   }
830
831   return success;
832 }
833
834 bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array,
835                                            uint32_t size,
836                                            bool horizontal )
837 {
838 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
839   bool success( true );
840
841   for( unsigned int i=0; i<size; ++i )
842   {
843     FontId fontId = array[i].fontId;
844
845     if( fontId > 0 &&
846         fontId-1 < mFontCache.size() )
847     {
848       FontFaceCacheItem& font = mFontCache[fontId-1];
849
850       if( ! font.mVectorFontId )
851       {
852         font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
853       }
854
855       mVectorFontCache->GetGlyphMetrics( font.mVectorFontId, array[i] );
856
857       // Vector metrics are in EMs, convert to pixels
858       const float scale = ( static_cast<float>( font.mRequestedPointSize ) * FROM_266 ) * static_cast<float>( mDpiVertical ) / POINTS_PER_INCH;
859       array[i].width    *= scale;
860       array[i].height   *= scale;
861       array[i].xBearing *= scale;
862       array[i].yBearing *= scale;
863       array[i].advance  *= scale;
864     }
865     else
866     {
867       success = false;
868     }
869   }
870
871   return success;
872 #else
873   return false;
874 #endif
875 }
876
877 void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data )
878 {
879   if( ( fontId > 0u ) &&
880       ( fontId - 1u < mFontCache.size() ) )
881   {
882     FT_Face ftFace = mFontCache[fontId - 1u].mFreeTypeFace;
883
884     FT_Error error;
885
886 #ifdef FREETYPE_BITMAP_SUPPORT
887     // Check to see if this is fixed size bitmap
888     if ( mFontCache[fontId - 1u].mIsFixedSizeBitmap )
889     {
890       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
891     }
892     else
893 #endif
894     {
895       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
896     }
897     if( FT_Err_Ok == error )
898     {
899       FT_Glyph glyph;
900       error = FT_Get_Glyph( ftFace->glyph, &glyph );
901
902       // Convert to bitmap if necessary
903       if ( FT_Err_Ok == error )
904       {
905         if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
906         {
907           error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
908           if ( FT_Err_Ok == error )
909           {
910             FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
911             ConvertBitmap( data, bitmapGlyph->bitmap );
912           }
913           else
914           {
915             DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
916           }
917         }
918         else
919         {
920           ConvertBitmap( data, ftFace->glyph->bitmap );
921         }
922
923         // Created FT_Glyph object must be released with FT_Done_Glyph
924         FT_Done_Glyph( glyph );
925       }
926     }
927     else
928     {
929       DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
930     }
931   }
932 }
933
934 PixelData FontClient::Plugin::CreateBitmap( FontId fontId,
935                                             GlyphIndex glyphIndex )
936 {
937   TextAbstraction::FontClient::GlyphBufferData data;
938
939   CreateBitmap( fontId, glyphIndex, data );
940
941   return PixelData::New( data.buffer,
942                          data.width * data.height * Pixel::GetBytesPerPixel( data.format ),
943                          data.width,
944                          data.height,
945                          data.format,
946                          PixelData::DELETE_ARRAY );
947 }
948
949 void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
950 {
951   blob = NULL;
952   blobLength = 0;
953
954 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
955   if( fontId > 0 &&
956       fontId-1 < mFontCache.size() )
957   {
958     FontFaceCacheItem& font = mFontCache[fontId-1];
959
960     if( ! font.mVectorFontId )
961     {
962       font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
963     }
964
965     mVectorFontCache->GetVectorBlob( font.mVectorFontId, fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
966   }
967 #endif
968 }
969
970 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize )
971 {
972   // First look into the cache if there is an ellipsis glyph for the requested point size.
973   for( Vector<EllipsisItem>::ConstIterator it = mEllipsisCache.Begin(),
974          endIt = mEllipsisCache.End();
975        it != endIt;
976        ++it )
977   {
978     const EllipsisItem& item = *it;
979
980     if( fabsf( item.requestedPointSize - requestedPointSize ) < Math::MACHINE_EPSILON_1000 )
981     {
982       // Use the glyph in the cache.
983       return item.glyph;
984     }
985   }
986
987   // No glyph has been found. Create one.
988   mEllipsisCache.PushBack( EllipsisItem() );
989   EllipsisItem& item = *( mEllipsisCache.End() - 1u );
990
991   item.requestedPointSize = requestedPointSize;
992
993   // Find a font for the ellipsis glyph.
994   item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
995                                        requestedPointSize,
996                                        false );
997
998   // Set the character index to access the glyph inside the font.
999   item.glyph.index = FT_Get_Char_Index( mFontCache[item.glyph.fontId-1].mFreeTypeFace,
1000                                         ELLIPSIS_CHARACTER );
1001
1002   GetBitmapMetrics( &item.glyph, 1u, true );
1003
1004   return item.glyph;
1005 }
1006
1007 bool FontClient::Plugin::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
1008 {
1009   FT_Error error = -1;
1010
1011 #ifdef FREETYPE_BITMAP_SUPPORT
1012   if( ( fontId > 0u ) &&
1013       ( fontId - 1u < mFontCache.size() ) )
1014   {
1015     const FontFaceCacheItem& item = mFontCache[fontId - 1u];
1016     FT_Face ftFace = item.mFreeTypeFace;
1017
1018     // Check to see if this is fixed size bitmap
1019     if( item.mIsFixedSizeBitmap )
1020     {
1021       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1022     }
1023   }
1024 #endif
1025
1026   return FT_Err_Ok == error;
1027 }
1028
1029 void FontClient::Plugin::InitSystemFonts()
1030 {
1031   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts \n");
1032
1033   FcFontSet* fontSet = GetFcFontSet();
1034
1035   if( fontSet )
1036   {
1037     // Reserve some space to avoid reallocations.
1038     mSystemFonts.reserve( fontSet->nfont );
1039
1040     for( int i = 0u; i < fontSet->nfont; ++i )
1041     {
1042       FcPattern* fontPattern = fontSet->fonts[i];
1043
1044       FontPath path;
1045
1046       // Skip fonts with no path
1047       if( GetFcString( fontPattern, FC_FILE, path ) )
1048       {
1049         mSystemFonts.push_back( FontDescription() );
1050         FontDescription& fontDescription = mSystemFonts.back();
1051
1052         fontDescription.path = path;
1053
1054         int width = 0;
1055         int weight = 0;
1056         int slant = 0;
1057         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
1058         GetFcInt( fontPattern, FC_WIDTH, width );
1059         GetFcInt( fontPattern, FC_WEIGHT, weight );
1060         GetFcInt( fontPattern, FC_SLANT, slant );
1061         fontDescription.width = IntToWidthType( width );
1062         fontDescription.weight = IntToWeightType( weight );
1063         fontDescription.slant = IntToSlantType( slant );
1064         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts font family(%s)\n", fontDescription.family.c_str() );
1065
1066       }
1067     }
1068
1069     FcFontSetDestroy( fontSet );
1070   }
1071 }
1072
1073 bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription )
1074 {
1075   FcResult result = FcResultMatch;
1076   FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
1077
1078   bool ret = false;
1079
1080   if( match )
1081   {
1082     int width = 0;
1083     int weight = 0;
1084     int slant = 0;
1085     GetFcString( match, FC_FILE, fontDescription.path );
1086     GetFcString( match, FC_FAMILY, fontDescription.family );
1087     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::MatchFontDescriptionToPattern matched:%s \n", fontDescription.family.c_str());
1088     GetFcInt( match, FC_WIDTH, width );
1089     GetFcInt( match, FC_WEIGHT, weight );
1090     GetFcInt( match, FC_SLANT, slant );
1091     fontDescription.width = IntToWidthType( width );
1092     fontDescription.weight = IntToWeightType( weight );
1093     fontDescription.slant = IntToSlantType( slant );
1094
1095     // destroyed the matched pattern
1096     FcPatternDestroy( match );
1097     ret = true;
1098   }
1099   return ret;
1100 }
1101
1102
1103 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription )
1104 {
1105   // create the cached font family lookup pattern
1106   // a pattern holds a set of names, each name refers to a property of the font
1107   FcPattern* fontFamilyPattern = FcPatternCreate();
1108
1109   // add a property to the pattern for the font family
1110   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
1111
1112   int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
1113   if( width < 0 )
1114   {
1115     // Use default.
1116     width = DEFAULT_FONT_WIDTH;
1117   }
1118
1119   int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
1120   if( weight < 0 )
1121   {
1122     // Use default.
1123     weight = DEFAULT_FONT_WEIGHT;
1124   }
1125
1126   int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
1127   if( slant < 0 )
1128   {
1129     // Use default.
1130     slant = DEFAULT_FONT_SLANT;
1131   }
1132
1133   FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
1134   FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
1135   FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
1136
1137   // Add a property of the pattern, to say we want to match TrueType fonts
1138   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
1139
1140   // modify the config, with the mFontFamilyPatterm
1141   FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
1142
1143   // provide default values for unspecified properties in the font pattern
1144   // e.g. patterns without a specified style or weight are set to Medium
1145   FcDefaultSubstitute( fontFamilyPattern );
1146
1147   return fontFamilyPattern;
1148 }
1149
1150 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
1151 {
1152   // create a new pattern.
1153   // a pattern holds a set of names, each name refers to a property of the font
1154   FcPattern* pattern = FcPatternCreate();
1155
1156   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
1157   FcObjectSet* objectSet = FcObjectSetCreate();
1158
1159   // build an object set from a list of property names
1160   FcObjectSetAdd( objectSet, FC_FILE );
1161   FcObjectSetAdd( objectSet, FC_FAMILY );
1162   FcObjectSetAdd( objectSet, FC_WIDTH );
1163   FcObjectSetAdd( objectSet, FC_WEIGHT );
1164   FcObjectSetAdd( objectSet, FC_SLANT );
1165
1166   // get a list of fonts
1167   // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
1168   FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
1169
1170   // clear up the object set
1171   if( objectSet )
1172   {
1173     FcObjectSetDestroy( objectSet );
1174   }
1175   // clear up the pattern
1176   if( pattern )
1177   {
1178     FcPatternDestroy( pattern );
1179   }
1180
1181   return fontset;
1182 }
1183
1184 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1185                                       const char* const n,
1186                                       std::string& string )
1187 {
1188   FcChar8* file = NULL;
1189   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1190
1191   if( FcResultMatch == retVal )
1192   {
1193     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1194     string.assign( reinterpret_cast<const char*>( file ) );
1195
1196     return true;
1197   }
1198
1199   return false;
1200 }
1201
1202 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
1203 {
1204   const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
1205
1206   if( FcResultMatch == retVal )
1207   {
1208     return true;
1209   }
1210
1211   return false;
1212 }
1213
1214 FontId FontClient::Plugin::CreateFont( const FontPath& path,
1215                                        PointSize26Dot6 requestedPointSize,
1216                                        PointSize26Dot6 actualPointSize,
1217                                        FaceIndex faceIndex,
1218                                        bool cacheDescription )
1219 {
1220   FontId id( 0 );
1221
1222   // Create & cache new font face
1223   FT_Face ftFace;
1224   int error = FT_New_Face( mFreeTypeLibrary,
1225                            path.c_str(),
1226                            0,
1227                            &ftFace );
1228
1229   if( FT_Err_Ok == error )
1230   {
1231     // Check to see if the font contains fixed sizes?
1232     if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1233     {
1234       // Ensure this size is available
1235       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1236       {
1237         if ( static_cast<FT_Pos>( actualPointSize ) == ftFace->available_sizes[ i ].size )
1238         {
1239           // Tell Freetype to use this size
1240           error = FT_Select_Size( ftFace, i );
1241           if ( FT_Err_Ok != error )
1242           {
1243             DALI_LOG_ERROR( "FreeType Select_Size error: %d\n", error );
1244           }
1245           else
1246           {
1247             float fixedWidth  = static_cast< float >( ftFace->available_sizes[ i ].width );
1248             float fixedHeight = static_cast< float >( ftFace->available_sizes[ i ].height );
1249
1250             // Indicate that the font is a fixed sized bitmap
1251             FontMetrics metrics( fixedHeight, // The ascender in pixels.
1252                                  0.0f,
1253                                  fixedHeight, // The height in pixels.
1254                                  0.0f,
1255                                  0.0f );
1256
1257             mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedWidth, fixedHeight ) );
1258             id = mFontCache.size();
1259
1260             if( cacheDescription )
1261             {
1262               CacheFontPath( ftFace, id, requestedPointSize, path );
1263             }
1264
1265             return id;
1266           }
1267         }
1268       }
1269
1270       // Can't find this size
1271       std::stringstream sizes;
1272       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1273       {
1274         if ( i )
1275         {
1276           sizes << ", ";
1277         }
1278         sizes << ftFace->available_sizes[ i ].size;
1279       }
1280       DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n",
1281                        path.c_str(), actualPointSize, sizes.str().c_str() );
1282     }
1283     else
1284     {
1285       error = FT_Set_Char_Size( ftFace,
1286                                 0,
1287                                 actualPointSize,
1288                                 mDpiHorizontal,
1289                                 mDpiVertical );
1290
1291       if( FT_Err_Ok == error )
1292       {
1293
1294         FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1295
1296         FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
1297                              static_cast< float >( ftMetrics.descender ) * FROM_266,
1298                              static_cast< float >( ftMetrics.height    ) * FROM_266,
1299                              static_cast< float >( ftFace->underline_position ) * FROM_266,
1300                              static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1301
1302         mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics ) );
1303         id = mFontCache.size();
1304
1305         if( cacheDescription )
1306         {
1307           CacheFontPath( ftFace, id, requestedPointSize, path );
1308         }
1309       }
1310       else
1311       {
1312         DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, actualPointSize );
1313       }
1314     }
1315   }
1316   else
1317   {
1318     DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
1319   }
1320
1321   return id;
1322 }
1323
1324 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap )
1325 {
1326   if( srcBitmap.width*srcBitmap.rows > 0 )
1327   {
1328     switch( srcBitmap.pixel_mode )
1329     {
1330       case FT_PIXEL_MODE_GRAY:
1331       {
1332         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
1333         {
1334           const unsigned int bufferSize = srcBitmap.width * srcBitmap.rows;
1335           data.buffer = new unsigned char[bufferSize];
1336           data.width = srcBitmap.width;
1337           data.height = srcBitmap.rows;
1338           data.format = Pixel::L8;
1339           memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1340         }
1341         break;
1342       }
1343
1344 #ifdef FREETYPE_BITMAP_SUPPORT
1345       case FT_PIXEL_MODE_BGRA:
1346       {
1347         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
1348         {
1349           const unsigned int bufferSize = srcBitmap.width * srcBitmap.rows * 4u;
1350           data.buffer = new unsigned char[bufferSize];
1351           data.width = srcBitmap.width;
1352           data.height = srcBitmap.rows;
1353           data.format = Pixel::BGRA8888;
1354           memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1355         }
1356         break;
1357       }
1358 #endif
1359       default:
1360       {
1361         DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" );
1362         break;
1363       }
1364     }
1365   }
1366 }
1367
1368 bool FontClient::Plugin::FindFont( const FontPath& path,
1369                                    PointSize26Dot6 requestedPointSize,
1370                                    FaceIndex faceIndex,
1371                                    FontId& fontId ) const
1372 {
1373   fontId = 0u;
1374   for( std::vector<FontFaceCacheItem>::const_iterator it = mFontCache.begin(),
1375          endIt = mFontCache.end();
1376        it != endIt;
1377        ++it, ++fontId )
1378   {
1379     const FontFaceCacheItem& cacheItem = *it;
1380
1381     if( cacheItem.mRequestedPointSize == requestedPointSize &&
1382         cacheItem.mFaceIndex == faceIndex &&
1383         cacheItem.mPath == path )
1384     {
1385       ++fontId;
1386       return true;
1387     }
1388   }
1389
1390   return false;
1391 }
1392
1393 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1394                                             FontDescriptionId& validatedFontId )
1395 {
1396   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont fontDescription family(%s)\n", fontDescription.family.c_str() );
1397
1398   validatedFontId = 0u;
1399
1400   for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
1401          endIt = mValidatedFontCache.end();
1402        it != endIt;
1403        ++it )
1404   {
1405     const FontDescriptionCacheItem& item = *it;
1406
1407     if( !fontDescription.family.empty() &&
1408         ( fontDescription.family == item.fontDescription.family ) &&
1409         ( fontDescription.width == item.fontDescription.width ) &&
1410         ( fontDescription.weight == item.fontDescription.weight ) &&
1411         ( fontDescription.slant == item.fontDescription.slant ) )
1412     {
1413       validatedFontId = item.index;
1414
1415       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont validated font family(%s) font id (%u) \n", fontDescription.family.c_str(), validatedFontId );
1416
1417       return true;
1418     }
1419   }
1420
1421   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont NOT VALIDATED return false\n" );
1422
1423   return false;
1424 }
1425
1426 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
1427                                                FontList*& fontList )
1428 {
1429   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList fontDescription family(%s)\n", fontDescription.family.c_str() );
1430
1431   fontList = NULL;
1432
1433   for( std::vector<FallbackCacheItem>::const_iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
1434        it != endIt;
1435        ++it )
1436   {
1437     const FallbackCacheItem& item = *it;
1438
1439     if( !fontDescription.family.empty() &&
1440         ( fontDescription.family == item.fontDescription.family ) &&
1441         ( fontDescription.width == item.fontDescription.width ) &&
1442         ( fontDescription.weight == item.fontDescription.weight ) &&
1443         ( fontDescription.slant == item.fontDescription.slant ) )
1444     {
1445       fontList = item.fallbackFonts;
1446
1447       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList font family(%s) font-list (%p) \n", fontDescription.family.c_str(), fontList );
1448
1449       return true;
1450     }
1451   }
1452
1453   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList NOT FOUND return false\n" );
1454
1455   return false;
1456 }
1457
1458 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1459                                    PointSize26Dot6 requestedPointSize,
1460                                    FontId& fontId )
1461 {
1462   fontId = 0u;
1463
1464   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
1465          endIt = mFontIdCache.end();
1466        it != endIt;
1467        ++it )
1468   {
1469     const FontIdCacheItem& item = *it;
1470
1471     if( ( validatedFontId == item.validatedFontId ) &&
1472         ( requestedPointSize == item.requestedPointSize ) )
1473     {
1474       fontId = item.fontId;
1475       return true;
1476     }
1477   }
1478
1479   return false;
1480 }
1481
1482 bool FontClient::Plugin::IsScalable( const FontPath& path )
1483 {
1484   FT_Face ftFace;
1485   int error = FT_New_Face( mFreeTypeLibrary,
1486                            path.c_str(),
1487                            0,
1488                            &ftFace );
1489   if( FT_Err_Ok != error )
1490   {
1491     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1492   }
1493   return ( ftFace->num_fixed_sizes == 0 );
1494 }
1495
1496 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1497 {
1498   // Create a font pattern.
1499   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1500
1501   FcResult result = FcResultMatch;
1502
1503   // match the pattern
1504   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1505   bool isScalable = true;
1506
1507   if( match )
1508   {
1509     // Get the path to the font file name.
1510     FontPath path;
1511     GetFcString( match, FC_FILE, path );
1512     isScalable = IsScalable( path );
1513   }
1514   else
1515   {
1516     DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1517                     fontDescription.family.c_str(),
1518                     fontDescription.width,
1519                     fontDescription.weight,
1520                     fontDescription.slant );
1521   }
1522   FcPatternDestroy( fontFamilyPattern );
1523   FcPatternDestroy( match );
1524   return isScalable;
1525 }
1526
1527 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1528 {
1529   // Empty the caller container
1530   sizes.Clear();
1531
1532   FT_Face ftFace;
1533   int error = FT_New_Face( mFreeTypeLibrary,
1534                            path.c_str(),
1535                            0,
1536                            &ftFace );
1537   if( FT_Err_Ok != error )
1538   {
1539     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1540   }
1541
1542   // Fetch the number of fixed sizes available
1543   if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1544   {
1545     for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1546     {
1547       sizes.PushBack( ftFace->available_sizes[ i ].size );
1548     }
1549   }
1550 }
1551
1552 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1553                                         Vector< PointSize26Dot6 >& sizes )
1554 {
1555   // Create a font pattern.
1556   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1557
1558   FcResult result = FcResultMatch;
1559
1560   // match the pattern
1561   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1562
1563   if( match )
1564   {
1565     // Get the path to the font file name.
1566     FontPath path;
1567     GetFcString( match, FC_FILE, path );
1568     GetFixedSizes( path, sizes );
1569   }
1570   else
1571   {
1572     DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1573                     fontDescription.family.c_str(),
1574                     fontDescription.width,
1575                     fontDescription.weight,
1576                     fontDescription.slant );
1577   }
1578   FcPatternDestroy( match );
1579   FcPatternDestroy( fontFamilyPattern );
1580 }
1581
1582 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize,  const FontPath& path )
1583 {
1584   FontDescription description;
1585   description.path = path;
1586   description.family = FontFamily( ftFace->family_name );
1587   description.weight = FontWeight::NONE;
1588   description.width = FontWidth::NONE;
1589   description.slant = FontSlant::NONE;
1590
1591   // Note FreeType doesn't give too much info to build a proper font style.
1592   if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1593   {
1594     description.slant = FontSlant::ITALIC;
1595   }
1596   if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1597   {
1598     description.weight = FontWeight::BOLD;
1599   }
1600
1601   FontDescriptionId validatedFontId = 0u;
1602   if( !FindValidatedFont( description,
1603                           validatedFontId ) )
1604   {
1605     // Set the index to the vector of paths to font file names.
1606     validatedFontId = mFontDescriptionCache.size();
1607
1608     // Add the path to the cache.
1609     mFontDescriptionCache.push_back( description );
1610
1611     // Cache the index and the font's description.
1612     FontDescriptionCacheItem item( description,
1613                                    validatedFontId );
1614
1615     mValidatedFontCache.push_back( item );
1616
1617     // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
1618     mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
1619                                              requestedPointSize,
1620                                              id ) );
1621   }
1622 }
1623
1624 } // namespace Internal
1625
1626 } // namespace TextAbstraction
1627
1628 } // namespace Dali