Imported Upstream version 2.6.5
[platform/upstream/freetype2.git] / src / cache / ftcbasic.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftcbasic.c                                                             */
4 /*                                                                         */
5 /*    The FreeType basic cache interface (body).                           */
6 /*                                                                         */
7 /*  Copyright 2003-2016 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(
142                 face,
143                 gindex,
144                 (FT_Int)family->attrs.load_flags | FT_LOAD_RENDER );
145       if ( !error )
146         *aface = face;
147     }
148
149     return error;
150   }
151
152
153   FT_CALLBACK_DEF( FT_Error )
154   ftc_basic_family_load_glyph( FTC_Family  ftcfamily,
155                                FT_UInt     gindex,
156                                FTC_Cache   cache,
157                                FT_Glyph   *aglyph )
158   {
159     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
160     FT_Error         error;
161     FTC_Scaler       scaler = &family->attrs.scaler;
162     FT_Face          face;
163     FT_Size          size;
164
165
166     /* we will now load the glyph image */
167     error = FTC_Manager_LookupSize( cache->manager,
168                                     scaler,
169                                     &size );
170     if ( !error )
171     {
172       face = size->face;
173
174       error = FT_Load_Glyph( face,
175                              gindex,
176                              (FT_Int)family->attrs.load_flags );
177       if ( !error )
178       {
179         if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP  ||
180              face->glyph->format == FT_GLYPH_FORMAT_OUTLINE )
181         {
182           /* ok, copy it */
183           FT_Glyph  glyph;
184
185
186           error = FT_Get_Glyph( face->glyph, &glyph );
187           if ( !error )
188           {
189             *aglyph = glyph;
190             goto Exit;
191           }
192         }
193         else
194           error = FT_THROW( Invalid_Argument );
195       }
196     }
197
198   Exit:
199     return error;
200   }
201
202
203   FT_CALLBACK_DEF( FT_Bool )
204   ftc_basic_gnode_compare_faceid( FTC_Node    ftcgnode,
205                                   FT_Pointer  ftcface_id,
206                                   FTC_Cache   cache,
207                                   FT_Bool*    list_changed )
208   {
209     FTC_GNode        gnode   = (FTC_GNode)ftcgnode;
210     FTC_FaceID       face_id = (FTC_FaceID)ftcface_id;
211     FTC_BasicFamily  family  = (FTC_BasicFamily)gnode->family;
212     FT_Bool          result;
213
214
215     if ( list_changed )
216       *list_changed = FALSE;
217     result = FT_BOOL( family->attrs.scaler.face_id == face_id );
218     if ( result )
219     {
220       /* we must call this function to avoid this node from appearing
221        * in later lookups with the same face_id!
222        */
223       FTC_GNode_UnselectFamily( gnode, cache );
224     }
225     return result;
226   }
227
228
229  /*
230   *
231   * basic image cache
232   *
233   */
234
235   static
236   const FTC_IFamilyClassRec  ftc_basic_image_family_class =
237   {
238     {
239       sizeof ( FTC_BasicFamilyRec ),
240       ftc_basic_family_compare,
241       ftc_basic_family_init,
242       0,                        /* FTC_MruNode_ResetFunc */
243       0                         /* FTC_MruNode_DoneFunc  */
244     },
245     ftc_basic_family_load_glyph
246   };
247
248
249   static
250   const FTC_GCacheClassRec  ftc_basic_image_cache_class =
251   {
252     {
253       ftc_inode_new,
254       ftc_inode_weight,
255       ftc_gnode_compare,
256       ftc_basic_gnode_compare_faceid,
257       ftc_inode_free,
258
259       sizeof ( FTC_GCacheRec ),
260       ftc_gcache_init,
261       ftc_gcache_done
262     },
263     (FTC_MruListClass)&ftc_basic_image_family_class
264   };
265
266
267   /* documentation is in ftcache.h */
268
269   FT_EXPORT_DEF( FT_Error )
270   FTC_ImageCache_New( FTC_Manager      manager,
271                       FTC_ImageCache  *acache )
272   {
273     return FTC_GCache_New( manager, &ftc_basic_image_cache_class,
274                            (FTC_GCache*)acache );
275   }
276
277
278   /* documentation is in ftcache.h */
279
280   FT_EXPORT_DEF( FT_Error )
281   FTC_ImageCache_Lookup( FTC_ImageCache  cache,
282                          FTC_ImageType   type,
283                          FT_UInt         gindex,
284                          FT_Glyph       *aglyph,
285                          FTC_Node       *anode )
286   {
287     FTC_BasicQueryRec  query;
288     FTC_Node           node = 0; /* make compiler happy */
289     FT_Error           error;
290     FT_Offset          hash;
291
292
293     /* some argument checks are delayed to `FTC_Cache_Lookup' */
294     if ( !aglyph )
295     {
296       error = FT_THROW( Invalid_Argument );
297       goto Exit;
298     }
299
300     *aglyph = NULL;
301     if ( anode )
302       *anode  = NULL;
303
304     if ( (FT_ULong)( type->flags - FT_INT_MIN ) > FT_UINT_MAX )
305       FT_TRACE1(( "FTC_ImageCache_Lookup:"
306                   " higher bits in load_flags 0x%x are dropped\n",
307                   (FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) ));
308
309     query.attrs.scaler.face_id = type->face_id;
310     query.attrs.scaler.width   = type->width;
311     query.attrs.scaler.height  = type->height;
312     query.attrs.load_flags     = (FT_UInt)type->flags;
313
314     query.attrs.scaler.pixel = 1;
315     query.attrs.scaler.x_res = 0;  /* make compilers happy */
316     query.attrs.scaler.y_res = 0;
317
318     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
319
320 #if 1  /* inlining is about 50% faster! */
321     FTC_GCACHE_LOOKUP_CMP( cache,
322                            ftc_basic_family_compare,
323                            FTC_GNode_Compare,
324                            hash, gindex,
325                            &query,
326                            node,
327                            error );
328 #else
329     error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
330                                hash, gindex,
331                                FTC_GQUERY( &query ),
332                                &node );
333 #endif
334     if ( !error )
335     {
336       *aglyph = FTC_INODE( node )->glyph;
337
338       if ( anode )
339       {
340         *anode = node;
341         node->ref_count++;
342       }
343     }
344
345   Exit:
346     return error;
347   }
348
349
350   /* documentation is in ftcache.h */
351
352   FT_EXPORT_DEF( FT_Error )
353   FTC_ImageCache_LookupScaler( FTC_ImageCache  cache,
354                                FTC_Scaler      scaler,
355                                FT_ULong        load_flags,
356                                FT_UInt         gindex,
357                                FT_Glyph       *aglyph,
358                                FTC_Node       *anode )
359   {
360     FTC_BasicQueryRec  query;
361     FTC_Node           node = 0; /* make compiler happy */
362     FT_Error           error;
363     FT_Offset          hash;
364
365
366     /* some argument checks are delayed to `FTC_Cache_Lookup' */
367     if ( !aglyph || !scaler )
368     {
369       error = FT_THROW( Invalid_Argument );
370       goto Exit;
371     }
372
373     *aglyph = NULL;
374     if ( anode )
375       *anode  = NULL;
376
377     /* `FT_Load_Glyph' and `FT_Load_Char' take FT_UInt flags */
378     if ( load_flags > FT_UINT_MAX )
379       FT_TRACE1(( "FTC_ImageCache_LookupScaler:"
380                   " higher bits in load_flags 0x%x are dropped\n",
381                   load_flags & ~((FT_ULong)FT_UINT_MAX) ));
382
383     query.attrs.scaler     = scaler[0];
384     query.attrs.load_flags = (FT_UInt)load_flags;
385
386     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
387
388     FTC_GCACHE_LOOKUP_CMP( cache,
389                            ftc_basic_family_compare,
390                            FTC_GNode_Compare,
391                            hash, gindex,
392                            &query,
393                            node,
394                            error );
395     if ( !error )
396     {
397       *aglyph = FTC_INODE( node )->glyph;
398
399       if ( anode )
400       {
401         *anode = node;
402         node->ref_count++;
403       }
404     }
405
406   Exit:
407     return error;
408   }
409
410
411   /*
412    *
413    * basic small bitmap cache
414    *
415    */
416
417   static
418   const FTC_SFamilyClassRec  ftc_basic_sbit_family_class =
419   {
420     {
421       sizeof ( FTC_BasicFamilyRec ),
422       ftc_basic_family_compare,
423       ftc_basic_family_init,
424       0,                            /* FTC_MruNode_ResetFunc */
425       0                             /* FTC_MruNode_DoneFunc  */
426     },
427     ftc_basic_family_get_count,
428     ftc_basic_family_load_bitmap
429   };
430
431
432   static
433   const FTC_GCacheClassRec  ftc_basic_sbit_cache_class =
434   {
435     {
436       ftc_snode_new,
437       ftc_snode_weight,
438       ftc_snode_compare,
439       ftc_basic_gnode_compare_faceid,
440       ftc_snode_free,
441
442       sizeof ( FTC_GCacheRec ),
443       ftc_gcache_init,
444       ftc_gcache_done
445     },
446     (FTC_MruListClass)&ftc_basic_sbit_family_class
447   };
448
449
450   /* documentation is in ftcache.h */
451
452   FT_EXPORT_DEF( FT_Error )
453   FTC_SBitCache_New( FTC_Manager     manager,
454                      FTC_SBitCache  *acache )
455   {
456     return FTC_GCache_New( manager, &ftc_basic_sbit_cache_class,
457                            (FTC_GCache*)acache );
458   }
459
460
461   /* documentation is in ftcache.h */
462
463   FT_EXPORT_DEF( FT_Error )
464   FTC_SBitCache_Lookup( FTC_SBitCache  cache,
465                         FTC_ImageType  type,
466                         FT_UInt        gindex,
467                         FTC_SBit      *ansbit,
468                         FTC_Node      *anode )
469   {
470     FT_Error           error;
471     FTC_BasicQueryRec  query;
472     FTC_Node           node = 0; /* make compiler happy */
473     FT_Offset          hash;
474
475
476     if ( anode )
477       *anode = NULL;
478
479     /* other argument checks delayed to `FTC_Cache_Lookup' */
480     if ( !ansbit )
481       return FT_THROW( Invalid_Argument );
482
483     *ansbit = NULL;
484
485     if ( (FT_ULong)( type->flags - FT_INT_MIN ) > FT_UINT_MAX )
486       FT_TRACE1(( "FTC_ImageCache_Lookup:"
487                   " higher bits in load_flags 0x%x are dropped\n",
488                   (FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) ));
489
490     query.attrs.scaler.face_id = type->face_id;
491     query.attrs.scaler.width   = type->width;
492     query.attrs.scaler.height  = type->height;
493     query.attrs.load_flags     = (FT_UInt)type->flags;
494
495     query.attrs.scaler.pixel = 1;
496     query.attrs.scaler.x_res = 0;  /* make compilers happy */
497     query.attrs.scaler.y_res = 0;
498
499     /* beware, the hash must be the same for all glyph ranges! */
500     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
501            gindex / FTC_SBIT_ITEMS_PER_NODE;
502
503 #if 1  /* inlining is about 50% faster! */
504     FTC_GCACHE_LOOKUP_CMP( cache,
505                            ftc_basic_family_compare,
506                            FTC_SNode_Compare,
507                            hash, gindex,
508                            &query,
509                            node,
510                            error );
511 #else
512     error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
513                                hash,
514                                gindex,
515                                FTC_GQUERY( &query ),
516                                &node );
517 #endif
518     if ( error )
519       goto Exit;
520
521     *ansbit = FTC_SNODE( node )->sbits +
522               ( gindex - FTC_GNODE( node )->gindex );
523
524     if ( anode )
525     {
526       *anode = node;
527       node->ref_count++;
528     }
529
530   Exit:
531     return error;
532   }
533
534
535   /* documentation is in ftcache.h */
536
537   FT_EXPORT_DEF( FT_Error )
538   FTC_SBitCache_LookupScaler( FTC_SBitCache  cache,
539                               FTC_Scaler     scaler,
540                               FT_ULong       load_flags,
541                               FT_UInt        gindex,
542                               FTC_SBit      *ansbit,
543                               FTC_Node      *anode )
544   {
545     FT_Error           error;
546     FTC_BasicQueryRec  query;
547     FTC_Node           node = 0; /* make compiler happy */
548     FT_Offset          hash;
549
550
551     if ( anode )
552         *anode = NULL;
553
554     /* other argument checks delayed to `FTC_Cache_Lookup' */
555     if ( !ansbit || !scaler )
556         return FT_THROW( Invalid_Argument );
557
558     *ansbit = NULL;
559
560     /* `FT_Load_Glyph' and `FT_Load_Char' take FT_UInt flags */
561     if ( load_flags > FT_UINT_MAX )
562       FT_TRACE1(( "FTC_ImageCache_LookupScaler:"
563                   " higher bits in load_flags 0x%x are dropped\n",
564                   load_flags & ~((FT_ULong)FT_UINT_MAX) ));
565
566     query.attrs.scaler     = scaler[0];
567     query.attrs.load_flags = (FT_UInt)load_flags;
568
569     /* beware, the hash must be the same for all glyph ranges! */
570     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
571              gindex / FTC_SBIT_ITEMS_PER_NODE;
572
573     FTC_GCACHE_LOOKUP_CMP( cache,
574                            ftc_basic_family_compare,
575                            FTC_SNode_Compare,
576                            hash, gindex,
577                            &query,
578                            node,
579                            error );
580     if ( error )
581       goto Exit;
582
583     *ansbit = FTC_SNODE( node )->sbits +
584               ( gindex - FTC_GNODE( node )->gindex );
585
586     if ( anode )
587     {
588       *anode = node;
589       node->ref_count++;
590     }
591
592   Exit:
593     return error;
594   }
595
596
597 /* END */