Fix signed / unsigned comparison warning on GCC4.8
[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       return;
191     }
192   }
193
194   DALI_LOG_ERROR( "FontClient::Plugin::GetDescription. No description found for the font ID %d\n", id );
195 }
196
197 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
198 {
199   const FontId index = id - 1u;
200
201   if( id > 0u &&
202       index < mFontCache.size() )
203   {
204     return ( *( mFontCache.begin() + index ) ).mPointSize;
205   }
206   else
207   {
208     DALI_LOG_ERROR( "FontClient::Plugin::GetPointSize. Invalid font ID %d\n", id );
209   }
210
211   return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
212 }
213
214 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
215                                             PointSize26Dot6 pointSize )
216 {
217   // Create the list of default fonts if it has not been created.
218   if( mDefaultFonts.empty() )
219   {
220     SetDefaultFontFamily( DEFAULT_FONT_FAMILY_NAME,
221                           DEFAULT_FONT_STYLE );
222   }
223
224   // Traverse the list of default fonts.
225   // Check for each default font if supports the character.
226
227   for( FontList::const_iterator it = mDefaultFonts.begin(),
228          endIt = mDefaultFonts.end();
229        it != endIt;
230        ++it )
231   {
232     const FontDescription& description = *it;
233
234     FcPattern* pattern = CreateFontFamilyPattern( description.family,
235                                                   description.style );
236
237     FcResult result = FcResultMatch;
238     FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
239
240     FcCharSet* charSet = NULL;
241     FcPatternGetCharSet( match, FC_CHARSET, 0u, &charSet );
242
243     if( FcCharSetHasChar( charSet, charcode ) )
244     {
245       return GetFontId( description.family,
246                         description.style,
247                         pointSize,
248                         0u );
249     }
250   }
251
252   return 0u;
253 }
254
255 FontId FontClient::Plugin::GetFontId( const FontPath& path,
256                                       PointSize26Dot6 pointSize,
257                                       FaceIndex faceIndex,
258                                       bool cacheDescription )
259 {
260   FontId id( 0 );
261
262   if( NULL != mFreeTypeLibrary )
263   {
264     FontId foundId(0);
265     if( FindFont( path, pointSize, faceIndex, foundId ) )
266     {
267       id = foundId;
268     }
269     else
270     {
271       id = CreateFont( path, pointSize, faceIndex, cacheDescription );
272     }
273   }
274
275   return id;
276 }
277
278 FontId FontClient::Plugin::GetFontId( const FontFamily& fontFamily,
279                                       const FontStyle& fontStyle,
280                                       PointSize26Dot6 pointSize,
281                                       FaceIndex faceIndex )
282 {
283   // This method uses three vectors which caches:
284   // * Pairs of non validated 'fontFamily, fontStyle' and an index to a vector with paths to font file names.
285   // * The path to font file names.
286   // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
287
288   // 1) Checks in the cache if the pair 'fontFamily, fontStyle' has been validated before.
289   //    If it was it gets an index to the vector with paths to font file names. Otherwise,
290   //    retrieves using font config a path to a font file name which matches with the pair
291   //    'fontFamily, fontStyle'. The path is stored in the chache.
292   //
293   // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
294   //    fon file names' exists. If exists, it gets the font id. If it doesn't it calls
295   //    the GetFontId() method with the path to the font file name and the point size to
296   //    get the font id.
297
298   // The font id to be returned.
299   FontId fontId = 0u;
300
301   // Check first if the pair font family and style have been validated before.
302   FontDescriptionId validatedFontId = 0u;
303
304   if( !FindValidatedFont( fontFamily,
305                           fontStyle,
306                           validatedFontId ) )
307   {
308     // Use font config to validate the font family name and font style.
309
310     // Create a font pattern.
311     FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamily,
312                                                             fontStyle );
313
314     FcResult result = FcResultMatch;
315
316     // match the pattern
317     FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
318
319     if( match )
320     {
321       // Get the path to the font file name.
322       FontDescription description;
323       GetFcString( match, FC_FILE, description.path );
324       GetFcString( match, FC_FAMILY, description.family );
325       GetFcString( match, FC_STYLE, description.style );
326
327       // Set the index to the vector of paths to font file names.
328       validatedFontId = mFontDescriptionCache.size();
329
330       // Add the path to the cache.
331       mFontDescriptionCache.push_back( description );
332
333       // Cache the index and the pair font family name, font style.
334       FontDescriptionCacheItem item( fontFamily, fontStyle, validatedFontId );
335       mValidatedFontCache.push_back( item );
336
337       // destroyed the matched pattern
338       FcPatternDestroy( match );
339     }
340     else
341     {
342       DALI_LOG_ERROR( "FontClient::Plugin::GetFontId failed for font %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
343     }
344
345     // destroy the pattern
346     FcPatternDestroy( fontFamilyPattern );
347   }
348
349   // Check if exists a pair 'validatedFontId, pointSize' in the cache.
350   if( !FindFont( validatedFontId, pointSize, fontId ) )
351   {
352     // Retrieve the font file name path.
353     const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
354
355     // Retrieve the font id. Do not cache the description as it has been already cached.
356     fontId = GetFontId( description.path,
357                         pointSize,
358                         faceIndex,
359                         false );
360
361     // Cache the pair 'validatedFontId, pointSize' to improve the following queries.
362     mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
363                                              pointSize,
364                                              fontId ) );
365   }
366
367   return fontId;
368 }
369
370 void FontClient::Plugin::GetFontMetrics( FontId fontId,
371                                          FontMetrics& metrics )
372 {
373   if( fontId > 0 &&
374       fontId-1 < mFontCache.size() )
375   {
376     metrics = mFontCache[fontId-1].mMetrics;
377   }
378   else
379   {
380     DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
381   }
382 }
383
384 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
385                                               Character charcode )
386 {
387   GlyphIndex index( 0 );
388
389   if( fontId > 0 &&
390       fontId-1 < mFontCache.size() )
391   {
392     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
393
394     index = FT_Get_Char_Index( ftFace, charcode );
395   }
396
397   return index;
398 }
399
400 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
401                                           uint32_t size,
402                                           bool horizontal )
403 {
404   bool success( true );
405
406   for( unsigned int i=0; i<size; ++i )
407   {
408     FontId fontId = array[i].fontId;
409
410     if( fontId > 0 &&
411         fontId-1 < mFontCache.size() )
412     {
413       FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
414
415       int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
416
417       if( FT_Err_Ok == error )
418       {
419         array[i].width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
420         array[i].height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
421         if( horizontal )
422         {
423           array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
424           array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
425           array[i].advance  = static_cast< float >( ftFace->glyph->metrics.horiAdvance ) * FROM_266;
426         }
427         else
428         {
429           array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
430           array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
431           array[i].advance  = static_cast< float >( ftFace->glyph->metrics.vertAdvance ) * FROM_266;
432         }
433       }
434       else
435       {
436         success = false;
437       }
438     }
439     else
440     {
441       success = false;
442     }
443   }
444
445   return success;
446 }
447
448 BitmapImage FontClient::Plugin::CreateBitmap( FontId fontId,
449                                               GlyphIndex glyphIndex )
450 {
451   BitmapImage bitmap;
452
453   if( fontId > 0 &&
454       fontId-1 < mFontCache.size() )
455   {
456     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
457
458     FT_Error error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
459     if( FT_Err_Ok == error )
460     {
461       FT_Glyph glyph;
462       error = FT_Get_Glyph( ftFace->glyph, &glyph );
463
464       // Convert to bitmap if necessary
465       if ( FT_Err_Ok == error )
466       {
467         if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
468         {
469           error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
470         }
471         else
472         {
473           DALI_LOG_ERROR( "FT_Glyph_To_Bitmap Failed with error: %d\n", error );
474         }
475       }
476       else
477       {
478         DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
479       }
480
481       if( FT_Err_Ok == error )
482       {
483         // Access the underlying bitmap data
484         FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
485         ConvertBitmap( bitmap, bitmapGlyph->bitmap );
486       }
487
488       // Created FT_Glyph object must be released with FT_Done_Glyph
489       FT_Done_Glyph( glyph );
490     }
491     else
492     {
493       DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
494     }
495   }
496
497   return bitmap;
498 }
499
500 void FontClient::Plugin::InitSystemFonts()
501 {
502   FcFontSet* fontSet = GetFcFontSet();
503
504   if( fontSet )
505   {
506     // Reserve some space to avoid reallocations.
507     mSystemFonts.reserve( fontSet->nfont );
508
509     for( int i = 0u; i < fontSet->nfont; ++i )
510     {
511       FcPattern* fontPattern = fontSet->fonts[i];
512
513       FontPath path;
514
515       // Skip fonts with no path
516       if( GetFcString( fontPattern, FC_FILE, path ) )
517       {
518         mSystemFonts.push_back( FontDescription() );
519         FontDescription& fontDescription = mSystemFonts.back();
520
521         fontDescription.path = path;
522
523         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
524         GetFcString( fontPattern, FC_STYLE, fontDescription.style );
525       }
526     }
527
528     FcFontSetDestroy( fontSet );
529   }
530 }
531
532 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontFamily& fontFamily,
533                                                         const FontStyle& fontStyle )
534 {
535   // create the cached font family lookup pattern
536   // a pattern holds a set of names, each name refers to a property of the font
537   FcPattern* fontFamilyPattern = FcPatternCreate();
538
539   // add a property to the pattern for the font family
540   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontFamily.c_str() ) );
541
542   // add a property to the pattern for the font family
543   FcPatternAddString( fontFamilyPattern, FC_STYLE, reinterpret_cast<const FcChar8*>( fontStyle.c_str() ) );
544
545   // Add a property of the pattern, to say we want to match TrueType fonts
546   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
547
548   // modify the config, with the mFontFamilyPatterm
549   FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
550
551   // provide default values for unspecified properties in the font pattern
552   // e.g. patterns without a specified style or weight are set to Medium
553   FcDefaultSubstitute( fontFamilyPattern );
554
555   return fontFamilyPattern;
556 }
557
558 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
559 {
560   // create a new pattern.
561   // a pattern holds a set of names, each name refers to a property of the font
562   FcPattern* pattern = FcPatternCreate();
563
564   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
565   FcObjectSet* objectSet = FcObjectSetCreate();
566
567   // build an object set from a list of property names
568   FcObjectSetAdd( objectSet, FC_FILE );
569   FcObjectSetAdd( objectSet, FC_FAMILY );
570   FcObjectSetAdd( objectSet, FC_STYLE );
571
572   // get a list of fonts
573   // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
574   FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
575
576   // clear up the object set
577   if( objectSet )
578   {
579     FcObjectSetDestroy( objectSet );
580   }
581   // clear up the pattern
582   if( pattern )
583   {
584     FcPatternDestroy( pattern );
585   }
586
587   return fontset;
588 }
589
590 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
591                                       const char* const n,
592                                       std::string& string )
593 {
594   FcChar8* file = NULL;
595   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
596
597   if( FcResultMatch == retVal )
598   {
599     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
600     string.assign( reinterpret_cast<const char*>( file ) );
601
602     return true;
603   }
604
605   return false;
606 }
607
608 FontId FontClient::Plugin::CreateFont( const FontPath& path,
609                                        PointSize26Dot6 pointSize,
610                                        FaceIndex faceIndex,
611                                        bool cacheDescription )
612 {
613   FontId id( 0 );
614
615   // Create & cache new font face
616   FT_Face ftFace;
617   int error = FT_New_Face( mFreeTypeLibrary,
618                            path.c_str(),
619                            0,
620                            &ftFace );
621
622   if( FT_Err_Ok == error )
623   {
624     error = FT_Set_Char_Size( ftFace,
625                               0,
626                               pointSize,
627                               mDpiHorizontal,
628                               mDpiVertical );
629
630     if( FT_Err_Ok == error )
631     {
632       id = mFontCache.size() + 1;
633
634       FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
635
636       FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
637                            static_cast< float >( ftMetrics.descender ) * FROM_266,
638                            static_cast< float >( ftMetrics.height    ) * FROM_266 );
639
640       mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics ) );
641
642       if( cacheDescription )
643       {
644         FontDescription description;
645         description.path = path;
646         description.family = FontFamily( ftFace->family_name );
647         description.style = FontStyle( ftFace->style_name );
648
649         mFontDescriptionCache.push_back( description );
650       }
651     }
652     else
653     {
654       DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", pointSize );
655     }
656   }
657   else
658   {
659     DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
660   }
661
662   return id;
663 }
664
665 void FontClient::Plugin::ConvertBitmap( BitmapImage& destBitmap,
666                                         FT_Bitmap srcBitmap )
667 {
668   if( srcBitmap.width*srcBitmap.rows > 0 )
669   {
670     // TODO - Support all pixel modes
671     if( FT_PIXEL_MODE_GRAY == srcBitmap.pixel_mode )
672     {
673       if( srcBitmap.pitch == static_cast< int >( srcBitmap.width ) )
674       {
675         destBitmap = BitmapImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
676
677         PixelBuffer* destBuffer = destBitmap.GetBuffer();
678         memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
679       }
680     }
681   }
682 }
683
684 bool FontClient::Plugin::FindFont( const FontPath& path,
685                                    PointSize26Dot6 pointSize,
686                                    FaceIndex faceIndex,
687                                    FontId& fontId ) const
688 {
689   fontId = 0u;
690   for( std::vector<CacheItem>::const_iterator it = mFontCache.begin(),
691          endIt = mFontCache.end();
692        it != endIt;
693        ++it, ++fontId )
694   {
695     const CacheItem& cacheItem = *it;
696
697     if( cacheItem.mPointSize == pointSize &&
698         cacheItem.mFaceIndex == faceIndex &&
699         cacheItem.mPath == path )
700     {
701       ++fontId;
702       return true;
703     }
704   }
705
706   return false;
707 }
708
709 bool FontClient::Plugin::FindValidatedFont( const FontFamily& fontFamily,
710                                             const FontStyle& fontStyle,
711                                             FontDescriptionId& validatedFontId )
712 {
713   validatedFontId = 0u;
714
715   for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
716          endIt = mValidatedFontCache.end();
717        it != endIt;
718        ++it )
719   {
720     const FontDescriptionCacheItem& item = *it;
721
722     if( ( fontFamily == item.fontFamily ) &&
723         ( fontStyle == item.fontStyle ) )
724     {
725       validatedFontId = item.index;
726
727       return true;
728     }
729   }
730
731   return false;
732 }
733
734 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
735                                    PointSize26Dot6 pointSize,
736                                    FontId& fontId )
737 {
738   fontId = 0u;
739
740   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
741          endIt = mFontIdCache.end();
742        it != endIt;
743        ++it )
744   {
745     const FontIdCacheItem& item = *it;
746
747     if( ( validatedFontId == item.validatedFontId ) &&
748         ( pointSize == item.pointSize ) )
749     {
750       fontId = item.fontId;
751       return true;
752     }
753   }
754
755   return false;
756 }
757
758 } // namespace Internal
759
760 } // namespace TextAbstraction
761
762 } // namespace Dali