tizen 2.3.1 release
[framework/graphics/freetype.git] / src / cache / ftcbasic.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftcbasic.c                                                             */
4 /*                                                                         */
5 /*    The FreeType basic cache interface (body).                           */
6 /*                                                                         */
7 /*  Copyright 2003-2007, 2009-2011, 2013, 2014 by                          */
8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9 /*                                                                         */
10 /*  This file is part of the FreeType project, and may only be used,       */
11 /*  modified, and distributed under the terms of the FreeType project      */
12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13 /*  this file you indicate that you have read the license and              */
14 /*  understand and accept it fully.                                        */
15 /*                                                                         */
16 /***************************************************************************/
17
18
19 #include <ft2build.h>
20 #include FT_INTERNAL_OBJECTS_H
21 #include FT_INTERNAL_DEBUG_H
22 #include FT_CACHE_H
23 #include "ftcglyph.h"
24 #include "ftcimage.h"
25 #include "ftcsbits.h"
26
27 #include "ftccback.h"
28 #include "ftcerror.h"
29
30 #define FT_COMPONENT  trace_cache
31
32
33   /*
34    *  Basic Families
35    *
36    */
37   typedef struct  FTC_BasicAttrRec_
38   {
39     FTC_ScalerRec  scaler;
40     FT_UInt        load_flags;
41
42   } FTC_BasicAttrRec, *FTC_BasicAttrs;
43
44 #define FTC_BASIC_ATTR_COMPARE( a, b )                                 \
45           FT_BOOL( FTC_SCALER_COMPARE( &(a)->scaler, &(b)->scaler ) && \
46                    (a)->load_flags == (b)->load_flags               )
47
48 #define FTC_BASIC_ATTR_HASH( a )                                   \
49           ( FTC_SCALER_HASH( &(a)->scaler ) + 31*(a)->load_flags )
50
51
52   typedef struct  FTC_BasicQueryRec_
53   {
54     FTC_GQueryRec     gquery;
55     FTC_BasicAttrRec  attrs;
56
57   } FTC_BasicQueryRec, *FTC_BasicQuery;
58
59
60   typedef struct  FTC_BasicFamilyRec_
61   {
62     FTC_FamilyRec     family;
63     FTC_BasicAttrRec  attrs;
64
65   } FTC_BasicFamilyRec, *FTC_BasicFamily;
66
67
68   FT_CALLBACK_DEF( FT_Bool )
69   ftc_basic_family_compare( FTC_MruNode  ftcfamily,
70                             FT_Pointer   ftcquery )
71   {
72     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
73     FTC_BasicQuery   query  = (FTC_BasicQuery)ftcquery;
74
75
76     return FTC_BASIC_ATTR_COMPARE( &family->attrs, &query->attrs );
77   }
78
79
80   FT_CALLBACK_DEF( FT_Error )
81   ftc_basic_family_init( FTC_MruNode  ftcfamily,
82                          FT_Pointer   ftcquery,
83                          FT_Pointer   ftccache )
84   {
85     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
86     FTC_BasicQuery   query  = (FTC_BasicQuery)ftcquery;
87     FTC_Cache        cache  = (FTC_Cache)ftccache;
88
89
90     FTC_Family_Init( FTC_FAMILY( family ), cache );
91     family->attrs = query->attrs;
92     return 0;
93   }
94
95
96   FT_CALLBACK_DEF( FT_UInt )
97   ftc_basic_family_get_count( FTC_Family   ftcfamily,
98                               FTC_Manager  manager )
99   {
100     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
101     FT_Error         error;
102     FT_Face          face;
103     FT_UInt          result = 0;
104
105
106     error = FTC_Manager_LookupFace( manager, family->attrs.scaler.face_id,
107                                     &face );
108
109     if ( error || !face )
110       return result;
111
112     if ( (FT_ULong)face->num_glyphs > FT_UINT_MAX || 0 > face->num_glyphs )
113       FT_TRACE1(( "ftc_basic_family_get_count:"
114                   " too large number of glyphs in this face, truncated\n",
115                   face->num_glyphs ));
116
117     if ( !error )
118       result = (FT_UInt)face->num_glyphs;
119
120     return result;
121   }
122
123
124   FT_CALLBACK_DEF( FT_Error )
125   ftc_basic_family_load_bitmap( FTC_Family   ftcfamily,
126                                 FT_UInt      gindex,
127                                 FTC_Manager  manager,
128                                 FT_Face     *aface )
129   {
130     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
131     FT_Error         error;
132     FT_Size          size;
133
134
135     error = FTC_Manager_LookupSize( manager, &family->attrs.scaler, &size );
136     if ( !error )
137     {
138       FT_Face  face = size->face;
139
140
141       error = FT_Load_Glyph( face, gindex,
142                              family->attrs.load_flags | FT_LOAD_RENDER );
143       if ( !error )
144         *aface = face;
145     }
146
147     return error;
148   }
149
150
151   FT_CALLBACK_DEF( FT_Error )
152   ftc_basic_family_load_glyph( FTC_Family  ftcfamily,
153                                FT_UInt     gindex,
154                                FTC_Cache   cache,
155                                FT_Glyph   *aglyph )
156   {
157     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
158     FT_Error         error;
159     FTC_Scaler       scaler = &family->attrs.scaler;
160     FT_Face          face;
161     FT_Size          size;
162
163
164     /* we will now load the glyph image */
165     error = FTC_Manager_LookupSize( cache->manager,
166                                     scaler,
167                                     &size );
168     if ( !error )
169     {
170       face = size->face;
171
172       error = FT_Load_Glyph( face, gindex, family->attrs.load_flags );
173       if ( !error )
174       {
175         if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP  ||
176              face->glyph->format == FT_GLYPH_FORMAT_OUTLINE )
177         {
178           /* ok, copy it */
179           FT_Glyph  glyph;
180
181
182           error = FT_Get_Glyph( face->glyph, &glyph );
183           if ( !error )
184           {
185             *aglyph = glyph;
186             goto Exit;
187           }
188         }
189         else
190           error = FT_THROW( Invalid_Argument );
191       }
192     }
193
194   Exit:
195     return error;
196   }
197
198
199   FT_CALLBACK_DEF( FT_Bool )
200   ftc_basic_gnode_compare_faceid( FTC_Node    ftcgnode,
201                                   FT_Pointer  ftcface_id,
202                                   FTC_Cache   cache,
203                                   FT_Bool*    list_changed )
204   {
205     FTC_GNode        gnode   = (FTC_GNode)ftcgnode;
206     FTC_FaceID       face_id = (FTC_FaceID)ftcface_id;
207     FTC_BasicFamily  family  = (FTC_BasicFamily)gnode->family;
208     FT_Bool          result;
209
210
211     if ( list_changed )
212       *list_changed = FALSE;
213     result = FT_BOOL( family->attrs.scaler.face_id == face_id );
214     if ( result )
215     {
216       /* we must call this function to avoid this node from appearing
217        * in later lookups with the same face_id!
218        */
219       FTC_GNode_UnselectFamily( gnode, cache );
220     }
221     return result;
222   }
223
224
225  /*
226   *
227   * basic image cache
228   *
229   */
230
231   static
232   const FTC_IFamilyClassRec  ftc_basic_image_family_class =
233   {
234     {
235       sizeof ( FTC_BasicFamilyRec ),
236       ftc_basic_family_compare,
237       ftc_basic_family_init,
238       0,                        /* FTC_MruNode_ResetFunc */
239       0                         /* FTC_MruNode_DoneFunc  */
240     },
241     ftc_basic_family_load_glyph
242   };
243
244
245   static
246   const FTC_GCacheClassRec  ftc_basic_image_cache_class =
247   {
248     {
249       ftc_inode_new,
250       ftc_inode_weight,
251       ftc_gnode_compare,
252       ftc_basic_gnode_compare_faceid,
253       ftc_inode_free,
254
255       sizeof ( FTC_GCacheRec ),
256       ftc_gcache_init,
257       ftc_gcache_done
258     },
259     (FTC_MruListClass)&ftc_basic_image_family_class
260   };
261
262
263   /* documentation is in ftcache.h */
264
265   FT_EXPORT_DEF( FT_Error )
266   FTC_ImageCache_New( FTC_Manager      manager,
267                       FTC_ImageCache  *acache )
268   {
269     return FTC_GCache_New( manager, &ftc_basic_image_cache_class,
270                            (FTC_GCache*)acache );
271   }
272
273
274   /* documentation is in ftcache.h */
275
276   FT_EXPORT_DEF( FT_Error )
277   FTC_ImageCache_Lookup( FTC_ImageCache  cache,
278                          FTC_ImageType   type,
279                          FT_UInt         gindex,
280                          FT_Glyph       *aglyph,
281                          FTC_Node       *anode )
282   {
283     FTC_BasicQueryRec  query;
284     FTC_Node           node = 0; /* make compiler happy */
285     FT_Error           error;
286     FT_PtrDist         hash;
287
288
289     /* some argument checks are delayed to `FTC_Cache_Lookup' */
290     if ( !aglyph )
291     {
292       error = FT_THROW( Invalid_Argument );
293       goto Exit;
294     }
295
296     *aglyph = NULL;
297     if ( anode )
298       *anode  = NULL;
299
300     if ( (FT_ULong)( type->flags - FT_INT_MIN ) > FT_UINT_MAX )
301       FT_TRACE1(( "FTC_ImageCache_Lookup:"
302                   " higher bits in load_flags 0x%x are dropped\n",
303                   type->flags & ~((FT_ULong)FT_UINT_MAX) ));
304
305     query.attrs.scaler.face_id = type->face_id;
306     query.attrs.scaler.width   = type->width;
307     query.attrs.scaler.height  = type->height;
308     query.attrs.load_flags     = (FT_UInt)type->flags;
309
310     query.attrs.scaler.pixel = 1;
311     query.attrs.scaler.x_res = 0;  /* make compilers happy */
312     query.attrs.scaler.y_res = 0;
313
314     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
315
316 #if 1  /* inlining is about 50% faster! */
317     FTC_GCACHE_LOOKUP_CMP( cache,
318                            ftc_basic_family_compare,
319                            FTC_GNode_Compare,
320                            hash, gindex,
321                            &query,
322                            node,
323                            error );
324 #else
325     error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
326                                hash, gindex,
327                                FTC_GQUERY( &query ),
328                                &node );
329 #endif
330     if ( !error )
331     {
332       *aglyph = FTC_INODE( node )->glyph;
333
334       if ( anode )
335       {
336         *anode = node;
337         node->ref_count++;
338       }
339     }
340
341   Exit:
342     return error;
343   }
344
345
346   /* documentation is in ftcache.h */
347
348   FT_EXPORT_DEF( FT_Error )
349   FTC_ImageCache_LookupScaler( FTC_ImageCache  cache,
350                                FTC_Scaler      scaler,
351                                FT_ULong        load_flags,
352                                FT_UInt         gindex,
353                                FT_Glyph       *aglyph,
354                                FTC_Node       *anode )
355   {
356     FTC_BasicQueryRec  query;
357     FTC_Node           node = 0; /* make compiler happy */
358     FT_Error           error;
359     FT_PtrDist         hash;
360
361
362     /* some argument checks are delayed to `FTC_Cache_Lookup' */
363     if ( !aglyph || !scaler )
364     {
365       error = FT_THROW( Invalid_Argument );
366       goto Exit;
367     }
368
369     *aglyph = NULL;
370     if ( anode )
371       *anode  = NULL;
372
373     /* `FT_Load_Glyph' and `FT_Load_Char' take FT_UInt flags */
374     if ( load_flags > FT_UINT_MAX )
375       FT_TRACE1(( "FTC_ImageCache_LookupScaler:"
376                   " higher bits in load_flags 0x%x are dropped\n",
377                   load_flags & ~((FT_ULong)FT_UINT_MAX) ));
378
379     query.attrs.scaler     = scaler[0];
380     query.attrs.load_flags = (FT_UInt)load_flags;
381
382     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
383
384     FTC_GCACHE_LOOKUP_CMP( cache,
385                            ftc_basic_family_compare,
386                            FTC_GNode_Compare,
387                            hash, gindex,
388                            &query,
389                            node,
390                            error );
391     if ( !error )
392     {
393       *aglyph = FTC_INODE( node )->glyph;
394
395       if ( anode )
396       {
397         *anode = node;
398         node->ref_count++;
399       }
400     }
401
402   Exit:
403     return error;
404   }
405
406
407   /*
408    *
409    * basic small bitmap cache
410    *
411    */
412
413   static
414   const FTC_SFamilyClassRec  ftc_basic_sbit_family_class =
415   {
416     {
417       sizeof ( FTC_BasicFamilyRec ),
418       ftc_basic_family_compare,
419       ftc_basic_family_init,
420       0,                            /* FTC_MruNode_ResetFunc */
421       0                             /* FTC_MruNode_DoneFunc  */
422     },
423     ftc_basic_family_get_count,
424     ftc_basic_family_load_bitmap
425   };
426
427
428   static
429   const FTC_GCacheClassRec  ftc_basic_sbit_cache_class =
430   {
431     {
432       ftc_snode_new,
433       ftc_snode_weight,
434       ftc_snode_compare,
435       ftc_basic_gnode_compare_faceid,
436       ftc_snode_free,
437
438       sizeof ( FTC_GCacheRec ),
439       ftc_gcache_init,
440       ftc_gcache_done
441     },
442     (FTC_MruListClass)&ftc_basic_sbit_family_class
443   };
444
445
446   /* documentation is in ftcache.h */
447
448   FT_EXPORT_DEF( FT_Error )
449   FTC_SBitCache_New( FTC_Manager     manager,
450                      FTC_SBitCache  *acache )
451   {
452     return FTC_GCache_New( manager, &ftc_basic_sbit_cache_class,
453                            (FTC_GCache*)acache );
454   }
455
456
457   /* documentation is in ftcache.h */
458
459   FT_EXPORT_DEF( FT_Error )
460   FTC_SBitCache_Lookup( FTC_SBitCache  cache,
461                         FTC_ImageType  type,
462                         FT_UInt        gindex,
463                         FTC_SBit      *ansbit,
464                         FTC_Node      *anode )
465   {
466     FT_Error           error;
467     FTC_BasicQueryRec  query;
468     FTC_Node           node = 0; /* make compiler happy */
469     FT_PtrDist         hash;
470
471
472     if ( anode )
473       *anode = NULL;
474
475     /* other argument checks delayed to `FTC_Cache_Lookup' */
476     if ( !ansbit )
477       return FT_THROW( Invalid_Argument );
478
479     *ansbit = NULL;
480
481     if ( (FT_ULong)( type->flags - FT_INT_MIN ) > FT_UINT_MAX )
482       FT_TRACE1(( "FTC_ImageCache_Lookup:"
483                   " higher bits in load_flags 0x%x are dropped\n",
484                   type->flags & ~((FT_ULong)FT_UINT_MAX) ));
485
486     query.attrs.scaler.face_id = type->face_id;
487     query.attrs.scaler.width   = type->width;
488     query.attrs.scaler.height  = type->height;
489     query.attrs.load_flags     = (FT_UInt)type->flags;
490
491     query.attrs.scaler.pixel = 1;
492     query.attrs.scaler.x_res = 0;  /* make compilers happy */
493     query.attrs.scaler.y_res = 0;
494
495     /* beware, the hash must be the same for all glyph ranges! */
496     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
497            gindex / FTC_SBIT_ITEMS_PER_NODE;
498
499 #if 1  /* inlining is about 50% faster! */
500     FTC_GCACHE_LOOKUP_CMP( cache,
501                            ftc_basic_family_compare,
502                            FTC_SNode_Compare,
503                            hash, gindex,
504                            &query,
505                            node,
506                            error );
507 #else
508     error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
509                                hash,
510                                gindex,
511                                FTC_GQUERY( &query ),
512                                &node );
513 #endif
514     if ( error )
515       goto Exit;
516
517     *ansbit = FTC_SNODE( node )->sbits +
518               ( gindex - FTC_GNODE( node )->gindex );
519
520     if ( anode )
521     {
522       *anode = node;
523       node->ref_count++;
524     }
525
526   Exit:
527     return error;
528   }
529
530
531   /* documentation is in ftcache.h */
532
533   FT_EXPORT_DEF( FT_Error )
534   FTC_SBitCache_LookupScaler( FTC_SBitCache  cache,
535                               FTC_Scaler     scaler,
536                               FT_ULong       load_flags,
537                               FT_UInt        gindex,
538                               FTC_SBit      *ansbit,
539                               FTC_Node      *anode )
540   {
541     FT_Error           error;
542     FTC_BasicQueryRec  query;
543     FTC_Node           node = 0; /* make compiler happy */
544     FT_PtrDist         hash;
545
546
547     if ( anode )
548         *anode = NULL;
549
550     /* other argument checks delayed to `FTC_Cache_Lookup' */
551     if ( !ansbit || !scaler )
552         return FT_THROW( Invalid_Argument );
553
554     *ansbit = NULL;
555
556     /* `FT_Load_Glyph' and `FT_Load_Char' take FT_UInt flags */
557     if ( load_flags > FT_UINT_MAX )
558       FT_TRACE1(( "FTC_ImageCache_LookupScaler:"
559                   " higher bits in load_flags 0x%x are dropped\n",
560                   load_flags & ~((FT_ULong)FT_UINT_MAX) ));
561
562     query.attrs.scaler     = scaler[0];
563     query.attrs.load_flags = (FT_UInt)load_flags;
564
565     /* beware, the hash must be the same for all glyph ranges! */
566     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
567              gindex / FTC_SBIT_ITEMS_PER_NODE;
568
569     FTC_GCACHE_LOOKUP_CMP( cache,
570                            ftc_basic_family_compare,
571                            FTC_SNode_Compare,
572                            hash, gindex,
573                            &query,
574                            node,
575                            error );
576     if ( error )
577       goto Exit;
578
579     *ansbit = FTC_SNODE( node )->sbits +
580               ( gindex - FTC_GNODE( node )->gindex );
581
582     if ( anode )
583     {
584       *anode = node;
585       node->ref_count++;
586     }
587
588   Exit:
589     return error;
590   }
591
592
593 /* END */