FontClient implementation
[platform/core/uifw/dali-adaptor.git] / text / dali / internal / text-abstraction / font-client-plugin-impl.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/text-abstraction/font-client-plugin-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/common/vector-wrapper.h>
23 #include <dali/public-api/text-abstraction/glyph-info.h>
24 #include <dali/integration-api/debug.h>
25
26 // EXTERNAL INCLUDES
27 #include <fontconfig/fontconfig.h>
28
29 /**
30  * Conversion from Fractional26.6 to float
31  */
32 namespace
33 {
34 const float FROM_266 = 1.0f / 64.0f;
35
36 const std::string FONT_FORMAT( "TrueType" );
37 const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
38 const std::string DEFAULT_FONT_STYLE( "Regular" );
39 }
40
41 namespace Dali
42 {
43
44 namespace TextAbstraction
45 {
46
47 namespace Internal
48 {
49
50 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontFamily& fontFamily,
51                                                                         const FontStyle& fontStyle,
52                                                                         FontDescriptionId index )
53 : fontFamily( fontFamily ),
54   fontStyle( fontStyle ),
55   index( index )
56 {}
57
58 FontClient::Plugin::FontIdCacheItem::FontIdCacheItem( FontDescriptionId validatedFontId,
59                                                       PointSize26Dot6 pointSize,
60                                                       FontId fontId )
61 : validatedFontId( validatedFontId ),
62   pointSize( pointSize ),
63   fontId( fontId )
64 {}
65
66 FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
67                                           const FontPath& path,
68                                           PointSize26Dot6 pointSize,
69                                           FaceIndex face,
70                                           const FontMetrics& metrics )
71 : mFreeTypeFace( ftFace ),
72   mPath( path ),
73   mPointSize( pointSize ),
74   mFaceIndex( face ),
75   mMetrics( metrics )
76 {}
77
78 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
79                             unsigned int verticalDpi )
80 : mFreeTypeLibrary( NULL ),
81   mDpiHorizontal( horizontalDpi ),
82   mDpiVertical( verticalDpi ),
83   mSystemFonts(),
84   mDefaultFonts(),
85   mFontCache(),
86   mValidatedFontCache(),
87   mFontDescriptionCache( 1u ),
88   mFontIdCache()
89 {
90   int error = FT_Init_FreeType( &mFreeTypeLibrary );
91   if( FT_Err_Ok != error )
92   {
93     DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
94   }
95 }
96
97 FontClient::Plugin::~Plugin()
98 {
99   FT_Done_FreeType( mFreeTypeLibrary );
100 }
101
102 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
103                                  unsigned int verticalDpi )
104 {
105   mDpiHorizontal = horizontalDpi;
106   mDpiVertical = verticalDpi;
107 }
108
109 void FontClient::Plugin::SetDefaultFontFamily( const FontFamily& fontFamilyName,
110                                                const FontStyle& fontStyle )
111 {
112   mDefaultFonts.clear();
113
114   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamilyName,
115                                                           fontStyle );
116
117   FcResult result = FcResultMatch;
118
119   // Match the pattern.
120   FcFontSet* fontSet = FcFontSort( NULL /* use default configure */,
121                                    fontFamilyPattern,
122                                    false /* don't trim */,
123                                    NULL,
124                                    &result );
125
126   if( NULL != fontSet )
127   {
128     // Reserve some space to avoid reallocations.
129     mDefaultFonts.reserve( fontSet->nfont );
130
131     for( int i = 0u; i < fontSet->nfont; ++i )
132     {
133       FcPattern* fontPattern = fontSet->fonts[i];
134
135       FontPath path;
136
137       // Skip fonts with no path
138       if( GetFcString( fontPattern, FC_FILE, path ) )
139       {
140         mDefaultFonts.push_back( FontDescription() );
141         FontDescription& fontDescription = mDefaultFonts.back();
142
143         fontDescription.path = path;
144
145         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
146         GetFcString( fontPattern, FC_STYLE, fontDescription.style );
147       }
148     }
149
150     FcFontSetDestroy( fontSet );
151   }
152
153   FcPatternDestroy( fontFamilyPattern );
154 }
155
156 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
157 {
158   if( mDefaultFonts.empty() )
159   {
160     SetDefaultFontFamily( DEFAULT_FONT_FAMILY_NAME,
161                           DEFAULT_FONT_STYLE );
162   }
163
164   defaultFonts = mDefaultFonts;
165 }
166
167 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
168 {
169   if( mSystemFonts.empty() )
170   {
171     InitSystemFonts();
172   }
173
174   systemFonts = mSystemFonts;
175 }
176
177 void FontClient::Plugin::GetDescription( FontId id,
178                                          FontDescription& fontDescription ) const
179 {
180   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
181          endIt = mFontIdCache.end();
182        it != endIt;
183        ++it )
184   {
185     const FontIdCacheItem& item = *it;
186
187     if( item.fontId == id )
188     {
189       fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
190     }
191   }
192
193   DALI_LOG_ERROR( "FontClient::Plugin::GetDescription. No description found for the font ID %d\n", id );
194 }
195
196 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
197 {
198   const FontId index = id - 1u;
199
200   if( id > 0u &&
201       index < mFontCache.size() )
202   {
203     return ( *( mFontCache.begin() + index ) ).mPointSize;
204   }
205   else
206   {
207     DALI_LOG_ERROR( "FontClient::Plugin::GetPointSize. Invalid font ID %d\n", id );
208   }
209
210   return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
211 }
212
213 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
214                                             PointSize26Dot6 pointSize )
215 {
216   // Create the list of default fonts if it has not been created.
217   if( mDefaultFonts.empty() )
218   {
219     SetDefaultFontFamily( DEFAULT_FONT_FAMILY_NAME,
220                           DEFAULT_FONT_STYLE );
221   }
222
223   // Traverse the list of default fonts.
224   // Check for each default font if supports the character.
225
226   for( FontList::const_iterator it = mDefaultFonts.begin(),
227          endIt = mDefaultFonts.end();
228        it != endIt;
229        ++it )
230   {
231     const FontDescription& description = *it;
232
233     FcPattern* pattern = CreateFontFamilyPattern( description.family,
234                                                   description.style );
235
236     FcResult result = FcResultMatch;
237     FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
238
239     FcCharSet* charSet = NULL;
240     FcPatternGetCharSet( match, FC_CHARSET, 0u, &charSet );
241
242     if( FcCharSetHasChar( charSet, charcode ) )
243     {
244       return GetFontId( description.family,
245                         description.style,
246                         pointSize,
247                         0u );
248     }
249   }
250
251   return 0u;
252 }
253
254 FontId FontClient::Plugin::GetFontId( const FontPath& path,
255                                       PointSize26Dot6 pointSize,
256                                       FaceIndex faceIndex,
257                                       bool cacheDescription )
258 {
259   FontId id( 0 );
260
261   if( NULL != mFreeTypeLibrary )
262   {
263     FontId foundId(0);
264     if( FindFont( path, pointSize, faceIndex, foundId ) )
265     {
266       id = foundId;
267     }
268     else
269     {
270       id = CreateFont( path, pointSize, faceIndex, cacheDescription );
271     }
272   }
273
274   return id;
275 }
276
277 FontId FontClient::Plugin::GetFontId( const FontFamily& fontFamily,
278                                       const FontStyle& fontStyle,
279                                       PointSize26Dot6 pointSize,
280                                       FaceIndex faceIndex )
281 {
282   // This method uses three vectors which caches:
283   // * Pairs of non validated 'fontFamily, fontStyle' and an index to a vector with paths to font file names.
284   // * The path to font file names.
285   // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
286
287   // 1) Checks in the cache if the pair 'fontFamily, fontStyle' has been validated before.
288   //    If it was it gets an index to the vector with paths to font file names. Otherwise,
289   //    retrieves using font config a path to a font file name which matches with the pair
290   //    'fontFamily, fontStyle'. The path is stored in the chache.
291   //
292   // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
293   //    fon file names' exists. If exists, it gets the font id. If it doesn't it calls
294   //    the GetFontId() method with the path to the font file name and the point size to
295   //    get the font id.
296
297   // The font id to be returned.
298   FontId fontId = 0u;
299
300   // Check first if the pair font family and style have been validated before.
301   FontDescriptionId validatedFontId = 0u;
302
303   if( !FindValidatedFont( fontFamily,
304                           fontStyle,
305                           validatedFontId ) )
306   {
307     // Use font config to validate the font family name and font style.
308
309     // Create a font pattern.
310     FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamily,
311                                                             fontStyle );
312
313     FcResult result = FcResultMatch;
314
315     // match the pattern
316     FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
317
318     if( match )
319     {
320       // Get the path to the font file name.
321       FontDescription description;
322       GetFcString( match, FC_FILE, description.path );
323       GetFcString( match, FC_FAMILY, description.family );
324       GetFcString( match, FC_STYLE, description.style );
325
326       // Set the index to the vector of paths to font file names.
327       validatedFontId = mFontDescriptionCache.size();
328
329       // Add the path to the cache.
330       mFontDescriptionCache.push_back( description );
331
332       // Cache the index and the pair font family name, font style.
333       FontDescriptionCacheItem item( fontFamily, fontStyle, validatedFontId );
334       mValidatedFontCache.push_back( item );
335
336       // destroyed the matched pattern
337       FcPatternDestroy( match );
338     }
339     else
340     {
341       DALI_LOG_ERROR( "FontClient::Plugin::GetFontId failed for font %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
342     }
343
344     // destroy the pattern
345     FcPatternDestroy( fontFamilyPattern );
346   }
347
348   // Check if exists a pair 'validatedFontId, pointSize' in the cache.
349   if( !FindFont( validatedFontId, pointSize, fontId ) )
350   {
351     // Retrieve the font file name path.
352     const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
353
354     // Retrieve the font id. Do not cache the description as it has been already cached.
355     fontId = GetFontId( description.path,
356                         pointSize,
357                         faceIndex,
358                         false );
359
360     // Cache the pair 'validatedFontId, pointSize' to improve the following queries.
361     mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
362                                              pointSize,
363                                              fontId ) );
364   }
365
366   return fontId;
367 }
368
369 void FontClient::Plugin::GetFontMetrics( FontId fontId,
370                                          FontMetrics& metrics )
371 {
372   if( fontId > 0 &&
373       fontId-1 < mFontCache.size() )
374   {
375     metrics = mFontCache[fontId-1].mMetrics;
376   }
377   else
378   {
379     DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
380   }
381 }
382
383 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
384                                               Character charcode )
385 {
386   GlyphIndex index( 0 );
387
388   if( fontId > 0 &&
389       fontId-1 < mFontCache.size() )
390   {
391     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
392
393     index = FT_Get_Char_Index( ftFace, charcode );
394   }
395
396   return index;
397 }
398
399 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
400                                           uint32_t size,
401                                           bool horizontal )
402 {
403   bool success( true );
404
405   for( unsigned int i=0; i<size; ++i )
406   {
407     FontId fontId = array[i].fontId;
408
409     if( fontId > 0 &&
410         fontId-1 < mFontCache.size() )
411     {
412       FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
413
414       int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
415
416       if( FT_Err_Ok == error )
417       {
418         array[i].width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
419         array[i].height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
420         if( horizontal )
421         {
422           array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
423           array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
424           array[i].advance  = static_cast< float >( ftFace->glyph->metrics.horiAdvance ) * FROM_266;
425         }
426         else
427         {
428           array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
429           array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
430           array[i].advance  = static_cast< float >( ftFace->glyph->metrics.vertAdvance ) * FROM_266;
431         }
432       }
433       else
434       {
435         success = false;
436       }
437     }
438     else
439     {
440       success = false;
441     }
442   }
443
444   return success;
445 }
446
447 BitmapImage FontClient::Plugin::CreateBitmap( FontId fontId,
448                                               GlyphIndex glyphIndex )
449 {
450   BitmapImage bitmap;
451
452   if( fontId > 0 &&
453       fontId-1 < mFontCache.size() )
454   {
455     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
456
457     FT_Error error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
458     if( FT_Err_Ok == error )
459     {
460       FT_Glyph glyph;
461       error = FT_Get_Glyph( ftFace->glyph, &glyph );
462
463       // Convert to bitmap if necessary
464       if ( FT_Err_Ok == error )
465       {
466         if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
467         {
468           error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
469         }
470         else
471         {
472           DALI_LOG_ERROR( "FT_Glyph_To_Bitmap Failed with error: %d\n", error );
473         }
474       }
475       else
476       {
477         DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
478       }
479
480       if( FT_Err_Ok == error )
481       {
482         // Access the underlying bitmap data
483         FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
484         ConvertBitmap( bitmap, bitmapGlyph->bitmap );
485       }
486
487       // Created FT_Glyph object must be released with FT_Done_Glyph
488       FT_Done_Glyph( glyph );
489     }
490     else
491     {
492       DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
493     }
494   }
495
496   return bitmap;
497 }
498
499 void FontClient::Plugin::InitSystemFonts()
500 {
501   FcFontSet* fontSet = GetFcFontSet();
502
503   if( fontSet )
504   {
505     // Reserve some space to avoid reallocations.
506     mSystemFonts.reserve( fontSet->nfont );
507
508     for( int i = 0u; i < fontSet->nfont; ++i )
509     {
510       FcPattern* fontPattern = fontSet->fonts[i];
511
512       FontPath path;
513
514       // Skip fonts with no path
515       if( GetFcString( fontPattern, FC_FILE, path ) )
516       {
517         mSystemFonts.push_back( FontDescription() );
518         FontDescription& fontDescription = mSystemFonts.back();
519
520         fontDescription.path = path;
521
522         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
523         GetFcString( fontPattern, FC_STYLE, fontDescription.style );
524       }
525     }
526
527     FcFontSetDestroy( fontSet );
528   }
529 }
530
531 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontFamily& fontFamily,
532                                                         const FontStyle& fontStyle )
533 {
534   // create the cached font family lookup pattern
535   // a pattern holds a set of names, each name refers to a property of the font
536   FcPattern* fontFamilyPattern = FcPatternCreate();
537
538   // add a property to the pattern for the font family
539   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontFamily.c_str() ) );
540
541   // add a property to the pattern for the font family
542   FcPatternAddString( fontFamilyPattern, FC_STYLE, reinterpret_cast<const FcChar8*>( fontStyle.c_str() ) );
543
544   // Add a property of the pattern, to say we want to match TrueType fonts
545   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
546
547   // modify the config, with the mFontFamilyPatterm
548   FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
549
550   // provide default values for unspecified properties in the font pattern
551   // e.g. patterns without a specified style or weight are set to Medium
552   FcDefaultSubstitute( fontFamilyPattern );
553
554   return fontFamilyPattern;
555 }
556
557 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
558 {
559   // create a new pattern.
560   // a pattern holds a set of names, each name refers to a property of the font
561   FcPattern* pattern = FcPatternCreate();
562
563   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
564   FcObjectSet* objectSet = FcObjectSetCreate();
565
566   // build an object set from a list of property names
567   FcObjectSetAdd( objectSet, FC_FILE );
568   FcObjectSetAdd( objectSet, FC_FAMILY );
569   FcObjectSetAdd( objectSet, FC_STYLE );
570
571   // get a list of fonts
572   // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
573   FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
574
575   // clear up the object set
576   if( objectSet )
577   {
578     FcObjectSetDestroy( objectSet );
579   }
580   // clear up the pattern
581   if( pattern )
582   {
583     FcPatternDestroy( pattern );
584   }
585
586   return fontset;
587 }
588
589 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
590                                       const char* const n,
591                                       std::string& string )
592 {
593   FcChar8* file = NULL;
594   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
595
596   if( FcResultMatch == retVal )
597   {
598     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
599     string.assign( reinterpret_cast<const char*>( file ) );
600
601     return true;
602   }
603
604   return false;
605 }
606
607 FontId FontClient::Plugin::CreateFont( const FontPath& path,
608                                        PointSize26Dot6 pointSize,
609                                        FaceIndex faceIndex,
610                                        bool cacheDescription )
611 {
612   FontId id( 0 );
613
614   // Create & cache new font face
615   FT_Face ftFace;
616   int error = FT_New_Face( mFreeTypeLibrary,
617                            path.c_str(),
618                            0,
619                            &ftFace );
620
621   if( FT_Err_Ok == error )
622   {
623     error = FT_Set_Char_Size( ftFace,
624                               0,
625                               pointSize,
626                               mDpiHorizontal,
627                               mDpiVertical );
628
629     if( FT_Err_Ok == error )
630     {
631       id = mFontCache.size() + 1;
632
633       FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
634
635       FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
636                            static_cast< float >( ftMetrics.descender ) * FROM_266,
637                            static_cast< float >( ftMetrics.height    ) * FROM_266 );
638
639       mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics ) );
640
641       if( cacheDescription )
642       {
643         FontDescription description;
644         description.path = path;
645         description.family = FontFamily( ftFace->family_name );
646         description.style = FontStyle( ftFace->style_name );
647
648         mFontDescriptionCache.push_back( description );
649       }
650     }
651     else
652     {
653       DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", pointSize );
654     }
655   }
656   else
657   {
658     DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
659   }
660
661   return id;
662 }
663
664 void FontClient::Plugin::ConvertBitmap( BitmapImage& destBitmap,
665                                         FT_Bitmap srcBitmap )
666 {
667   if( srcBitmap.width*srcBitmap.rows > 0 )
668   {
669     // TODO - Support all pixel modes
670     if( FT_PIXEL_MODE_GRAY == srcBitmap.pixel_mode )
671     {
672       if( srcBitmap.pitch == srcBitmap.width )
673       {
674         destBitmap = BitmapImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
675
676         PixelBuffer* destBuffer = destBitmap.GetBuffer();
677         memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
678       }
679     }
680   }
681 }
682
683 bool FontClient::Plugin::FindFont( const FontPath& path,
684                                    PointSize26Dot6 pointSize,
685                                    FaceIndex faceIndex,
686                                    FontId& fontId ) const
687 {
688   fontId = 0u;
689   for( std::vector<CacheItem>::const_iterator it = mFontCache.begin(),
690          endIt = mFontCache.end();
691        it != endIt;
692        ++it, ++fontId )
693   {
694     const CacheItem& cacheItem = *it;
695
696     if( cacheItem.mPointSize == pointSize &&
697         cacheItem.mFaceIndex == faceIndex &&
698         cacheItem.mPath == path )
699     {
700       ++fontId;
701       return true;
702     }
703   }
704
705   return false;
706 }
707
708 bool FontClient::Plugin::FindValidatedFont( const FontFamily& fontFamily,
709                                             const FontStyle& fontStyle,
710                                             FontDescriptionId& validatedFontId )
711 {
712   validatedFontId = 0u;
713
714   for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
715          endIt = mValidatedFontCache.end();
716        it != endIt;
717        ++it )
718   {
719     const FontDescriptionCacheItem& item = *it;
720
721     if( ( fontFamily == item.fontFamily ) &&
722         ( fontStyle == item.fontStyle ) )
723     {
724       validatedFontId = item.index;
725
726       return true;
727     }
728   }
729
730   return false;
731 }
732
733 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
734                                    PointSize26Dot6 pointSize,
735                                    FontId& fontId )
736 {
737   fontId = 0u;
738
739   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
740          endIt = mFontIdCache.end();
741        it != endIt;
742        ++it )
743   {
744     const FontIdCacheItem& item = *it;
745
746     if( ( validatedFontId == item.validatedFontId ) &&
747         ( pointSize == item.pointSize ) )
748     {
749       fontId = item.fontId;
750       return true;
751     }
752   }
753
754   return false;
755 }
756
757 } // namespace Internal
758
759 } // namespace TextAbstraction
760
761 } // namespace Dali