9fb6ddb1ee43a24c002407f920bb355ce72caca7
[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, 2004, 2005, 2006, 2007, 2009, 2010 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_DEBUG_H
21 #include FT_CACHE_H
22 #include "ftcglyph.h"
23 #include "ftcimage.h"
24 #include "ftcsbits.h"
25
26 #include "ftccback.h"
27 #include "ftcerror.h"
28
29 #define FT_COMPONENT  trace_cache
30
31
32 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
33
34   /*
35    *  These structures correspond to the FTC_Font and FTC_ImageDesc types
36    *  that were defined in version 2.1.7.
37    */
38   typedef struct  FTC_OldFontRec_
39   {
40     FTC_FaceID  face_id;
41     FT_UShort   pix_width;
42     FT_UShort   pix_height;
43
44   } FTC_OldFontRec, *FTC_OldFont;
45
46
47   typedef struct  FTC_OldImageDescRec_
48   {
49     FTC_OldFontRec  font;
50     FT_UInt32       flags;
51
52   } FTC_OldImageDescRec, *FTC_OldImageDesc;
53
54
55   /*
56    *  Notice that FTC_OldImageDescRec and FTC_ImageTypeRec are nearly
57    *  identical, bit-wise.  The only difference is that the `width' and
58    *  `height' fields are expressed as 16-bit integers in the old structure,
59    *  and as normal `int' in the new one.
60    *
61    *  We are going to perform a weird hack to detect which structure is
62    *  being passed to the image and sbit caches.  If the new structure's
63    *  `width' is larger than 0x10000, we assume that we are really receiving
64    *  an FTC_OldImageDesc.
65    */
66
67 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
68
69
70   /*
71    *  Basic Families
72    *
73    */
74   typedef struct  FTC_BasicAttrRec_
75   {
76     FTC_ScalerRec  scaler;
77     FT_UInt        load_flags;
78
79   } FTC_BasicAttrRec, *FTC_BasicAttrs;
80
81 #define FTC_BASIC_ATTR_COMPARE( a, b )                                 \
82           FT_BOOL( FTC_SCALER_COMPARE( &(a)->scaler, &(b)->scaler ) && \
83                    (a)->load_flags == (b)->load_flags               )
84
85 #define FTC_BASIC_ATTR_HASH( a )                                   \
86           ( FTC_SCALER_HASH( &(a)->scaler ) + 31*(a)->load_flags )
87
88
89   typedef struct  FTC_BasicQueryRec_
90   {
91     FTC_GQueryRec     gquery;
92     FTC_BasicAttrRec  attrs;
93
94   } FTC_BasicQueryRec, *FTC_BasicQuery;
95
96
97   typedef struct  FTC_BasicFamilyRec_
98   {
99     FTC_FamilyRec     family;
100     FTC_BasicAttrRec  attrs;
101
102   } FTC_BasicFamilyRec, *FTC_BasicFamily;
103
104
105   FT_CALLBACK_DEF( FT_Bool )
106   ftc_basic_family_compare( FTC_MruNode  ftcfamily,
107                             FT_Pointer   ftcquery )
108   {
109     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
110     FTC_BasicQuery   query  = (FTC_BasicQuery)ftcquery;
111
112
113     return FTC_BASIC_ATTR_COMPARE( &family->attrs, &query->attrs );
114   }
115
116
117   FT_CALLBACK_DEF( FT_Error )
118   ftc_basic_family_init( FTC_MruNode  ftcfamily,
119                          FT_Pointer   ftcquery,
120                          FT_Pointer   ftccache )
121   {
122     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
123     FTC_BasicQuery   query  = (FTC_BasicQuery)ftcquery;
124     FTC_Cache        cache  = (FTC_Cache)ftccache;
125
126
127     FTC_Family_Init( FTC_FAMILY( family ), cache );
128     family->attrs = query->attrs;
129     return 0;
130   }
131
132
133   FT_CALLBACK_DEF( FT_UInt )
134   ftc_basic_family_get_count( FTC_Family   ftcfamily,
135                               FTC_Manager  manager )
136   {
137     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
138     FT_Error         error;
139     FT_Face          face;
140     FT_UInt          result = 0;
141
142
143     error = FTC_Manager_LookupFace( manager, family->attrs.scaler.face_id,
144                                     &face );
145
146     if ( error || !face )
147       return result;
148
149     if ( (FT_ULong)face->num_glyphs > FT_UINT_MAX || 0 > face->num_glyphs )
150     {
151       FT_TRACE1(( "ftc_basic_family_get_count: too large number of glyphs " ));
152       FT_TRACE1(( "in this face, truncated\n", face->num_glyphs ));
153     }
154
155     if ( !error )
156       result = (FT_UInt)face->num_glyphs;
157
158     return result;
159   }
160
161
162   FT_CALLBACK_DEF( FT_Error )
163   ftc_basic_family_load_bitmap( FTC_Family   ftcfamily,
164                                 FT_UInt      gindex,
165                                 FTC_Manager  manager,
166                                 FT_Face     *aface )
167   {
168     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
169     FT_Error         error;
170     FT_Size          size;
171
172
173     error = FTC_Manager_LookupSize( manager, &family->attrs.scaler, &size );
174     if ( !error )
175     {
176       FT_Face  face = size->face;
177
178
179       error = FT_Load_Glyph( face, gindex,
180                              family->attrs.load_flags | FT_LOAD_RENDER );
181       if ( !error )
182         *aface = face;
183     }
184
185     return error;
186   }
187
188
189   FT_CALLBACK_DEF( FT_Error )
190   ftc_basic_family_load_glyph( FTC_Family  ftcfamily,
191                                FT_UInt     gindex,
192                                FTC_Cache   cache,
193                                FT_Glyph   *aglyph )
194   {
195     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
196     FT_Error         error;
197     FTC_Scaler       scaler = &family->attrs.scaler;
198     FT_Face          face;
199     FT_Size          size;
200
201
202     /* we will now load the glyph image */
203     error = FTC_Manager_LookupSize( cache->manager,
204                                     scaler,
205                                     &size );
206     if ( !error )
207     {
208       face = size->face;
209
210       error = FT_Load_Glyph( face, gindex, family->attrs.load_flags );
211       if ( !error )
212       {
213         if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP  ||
214              face->glyph->format == FT_GLYPH_FORMAT_OUTLINE )
215         {
216           /* ok, copy it */
217           FT_Glyph  glyph;
218
219
220           error = FT_Get_Glyph( face->glyph, &glyph );
221           if ( !error )
222           {
223             *aglyph = glyph;
224             goto Exit;
225           }
226         }
227         else
228           error = FTC_Err_Invalid_Argument;
229       }
230     }
231
232   Exit:
233     return error;
234   }
235
236
237   FT_CALLBACK_DEF( FT_Bool )
238   ftc_basic_gnode_compare_faceid( FTC_Node    ftcgnode,
239                                   FT_Pointer  ftcface_id,
240                                   FTC_Cache   cache )
241   {
242     FTC_GNode        gnode   = (FTC_GNode)ftcgnode;
243     FTC_FaceID       face_id = (FTC_FaceID)ftcface_id;
244     FTC_BasicFamily  family  = (FTC_BasicFamily)gnode->family;
245     FT_Bool          result;
246
247
248     result = FT_BOOL( family->attrs.scaler.face_id == face_id );
249     if ( result )
250     {
251       /* we must call this function to avoid this node from appearing
252        * in later lookups with the same face_id!
253        */
254       FTC_GNode_UnselectFamily( gnode, cache );
255     }
256     return result;
257   }
258
259
260  /*
261   *
262   * basic image cache
263   *
264   */
265
266   FT_CALLBACK_TABLE_DEF
267   const FTC_IFamilyClassRec  ftc_basic_image_family_class =
268   {
269     {
270       sizeof ( FTC_BasicFamilyRec ),
271       ftc_basic_family_compare,
272       ftc_basic_family_init,
273       0,                        /* FTC_MruNode_ResetFunc */
274       0                         /* FTC_MruNode_DoneFunc  */
275     },
276     ftc_basic_family_load_glyph
277   };
278
279
280   FT_CALLBACK_TABLE_DEF
281   const FTC_GCacheClassRec  ftc_basic_image_cache_class =
282   {
283     {
284       ftc_inode_new,
285       ftc_inode_weight,
286       ftc_gnode_compare,
287       ftc_basic_gnode_compare_faceid,
288       ftc_inode_free,
289
290       sizeof ( FTC_GCacheRec ),
291       ftc_gcache_init,
292       ftc_gcache_done
293     },
294     (FTC_MruListClass)&ftc_basic_image_family_class
295   };
296
297
298   /* documentation is in ftcache.h */
299
300   FT_EXPORT_DEF( FT_Error )
301   FTC_ImageCache_New( FTC_Manager      manager,
302                       FTC_ImageCache  *acache )
303   {
304     return FTC_GCache_New( manager, &ftc_basic_image_cache_class,
305                            (FTC_GCache*)acache );
306   }
307
308
309   /* documentation is in ftcache.h */
310
311   FT_EXPORT_DEF( FT_Error )
312   FTC_ImageCache_Lookup( FTC_ImageCache  cache,
313                          FTC_ImageType   type,
314                          FT_UInt         gindex,
315                          FT_Glyph       *aglyph,
316                          FTC_Node       *anode )
317   {
318     FTC_BasicQueryRec  query;
319     FTC_Node           node = 0; /* make compiler happy */
320     FT_Error           error;
321     FT_UInt32          hash;
322
323
324     /* some argument checks are delayed to FTC_Cache_Lookup */
325     if ( !aglyph )
326     {
327       error = FTC_Err_Invalid_Argument;
328       goto Exit;
329     }
330
331     *aglyph = NULL;
332     if ( anode )
333       *anode  = NULL;
334
335 #if defined( FT_CONFIG_OPTION_OLD_INTERNALS ) && ( FT_INT_MAX > 0xFFFFU )
336
337     /*
338      *  This one is a major hack used to detect whether we are passed a
339      *  regular FTC_ImageType handle, or a legacy FTC_OldImageDesc one.
340      */
341     if ( (FT_ULong)type->width >= 0x10000L )
342     {
343       FTC_OldImageDesc  desc = (FTC_OldImageDesc)type;
344
345
346       query.attrs.scaler.face_id = desc->font.face_id;
347       query.attrs.scaler.width   = desc->font.pix_width;
348       query.attrs.scaler.height  = desc->font.pix_height;
349       query.attrs.load_flags     = desc->flags;
350     }
351     else
352
353 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
354
355     {
356       if ( (FT_ULong)(type->flags - FT_INT_MIN) > FT_UINT_MAX )
357       {
358         FT_TRACE1(( "FTC_ImageCache_Lookup: higher bits in load_flags" ));
359         FT_TRACE1(( "0x%x are dropped\n", (type->flags & ~((FT_ULong)FT_UINT_MAX)) ));
360       }
361
362       query.attrs.scaler.face_id = type->face_id;
363       query.attrs.scaler.width   = type->width;
364       query.attrs.scaler.height  = type->height;
365       query.attrs.load_flags     = (FT_UInt)type->flags;
366     }
367
368     query.attrs.scaler.pixel = 1;
369     query.attrs.scaler.x_res = 0;  /* make compilers happy */
370     query.attrs.scaler.y_res = 0;
371
372     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
373
374 #if 1  /* inlining is about 50% faster! */
375     FTC_GCACHE_LOOKUP_CMP( cache,
376                            ftc_basic_family_compare,
377                            FTC_GNode_Compare,
378                            hash, gindex,
379                            &query,
380                            node,
381                            error );
382 #else
383     error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
384                                hash, gindex,
385                                FTC_GQUERY( &query ),
386                                &node );
387 #endif
388     if ( !error )
389     {
390       *aglyph = FTC_INODE( node )->glyph;
391
392       if ( anode )
393       {
394         *anode = node;
395         node->ref_count++;
396       }
397     }
398
399   Exit:
400     return error;
401   }
402
403
404   /* documentation is in ftcache.h */
405
406   FT_EXPORT_DEF( FT_Error )
407   FTC_ImageCache_LookupScaler( FTC_ImageCache  cache,
408                                FTC_Scaler      scaler,
409                                FT_ULong        load_flags,
410                                FT_UInt         gindex,
411                                FT_Glyph       *aglyph,
412                                FTC_Node       *anode )
413   {
414     FTC_BasicQueryRec  query;
415     FTC_Node           node = 0; /* make compiler happy */
416     FT_Error           error;
417     FT_UInt32          hash;
418
419
420     /* some argument checks are delayed to FTC_Cache_Lookup */
421     if ( !aglyph || !scaler )
422     {
423       error = FTC_Err_Invalid_Argument;
424       goto Exit;
425     }
426
427     *aglyph = NULL;
428     if ( anode )
429       *anode  = NULL;
430
431     /* FT_Load_Glyph(), FT_Load_Char() take FT_UInt flags */
432     if ( load_flags > FT_UINT_MAX )
433     {
434       FT_TRACE1(( "FTC_ImageCache_LookupScaler: higher bits in load_flags" ));
435       FT_TRACE1(( "0x%x are dropped\n", (load_flags & ~((FT_ULong)FT_UINT_MAX)) ));
436     }
437
438     query.attrs.scaler     = scaler[0];
439     query.attrs.load_flags = (FT_UInt)load_flags;
440
441     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
442
443     FTC_GCACHE_LOOKUP_CMP( cache,
444                            ftc_basic_family_compare,
445                            FTC_GNode_Compare,
446                            hash, gindex,
447                            &query,
448                            node,
449                            error );
450     if ( !error )
451     {
452       *aglyph = FTC_INODE( node )->glyph;
453
454       if ( anode )
455       {
456         *anode = node;
457         node->ref_count++;
458       }
459     }
460
461   Exit:
462     return error;
463   }
464
465
466   
467 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
468
469   /* yet another backwards-legacy structure */
470   typedef struct  FTC_OldImage_Desc_
471   {
472     FTC_FontRec  font;
473     FT_UInt      image_type;
474
475   } FTC_OldImage_Desc;
476
477
478 #define FTC_OLD_IMAGE_FORMAT( x )  ( (x) & 7 )
479
480
481 #define ftc_old_image_format_bitmap    0x0000
482 #define ftc_old_image_format_outline   0x0001
483
484 #define ftc_old_image_format_mask      0x000F
485
486 #define ftc_old_image_flag_monochrome  0x0010
487 #define ftc_old_image_flag_unhinted    0x0020
488 #define ftc_old_image_flag_autohinted  0x0040
489 #define ftc_old_image_flag_unscaled    0x0080
490 #define ftc_old_image_flag_no_sbits    0x0100
491
492   /* monochrome bitmap */
493 #define ftc_old_image_mono             ftc_old_image_format_bitmap   | \
494                                        ftc_old_image_flag_monochrome
495
496   /* anti-aliased bitmap */
497 #define ftc_old_image_grays            ftc_old_image_format_bitmap
498
499   /* scaled outline */
500 #define ftc_old_image_outline          ftc_old_image_format_outline
501
502
503   static void
504   ftc_image_type_from_old_desc( FTC_ImageType       typ,
505                                 FTC_OldImage_Desc*  desc )
506   {
507     typ->face_id = desc->font.face_id;
508     typ->width   = desc->font.pix_width;
509     typ->height  = desc->font.pix_height;
510
511     /* convert image type flags to load flags */
512     {
513       FT_UInt  load_flags = FT_LOAD_DEFAULT;
514       FT_UInt  type       = desc->image_type;
515
516
517       /* determine load flags, depending on the font description's */
518       /* image type                                                */
519
520       if ( FTC_OLD_IMAGE_FORMAT( type ) == ftc_old_image_format_bitmap )
521       {
522         if ( type & ftc_old_image_flag_monochrome )
523           load_flags |= FT_LOAD_MONOCHROME;
524
525         /* disable embedded bitmaps loading if necessary */
526         if ( type & ftc_old_image_flag_no_sbits )
527           load_flags |= FT_LOAD_NO_BITMAP;
528       }
529       else
530       {
531         /* we want an outline, don't load embedded bitmaps */
532         load_flags |= FT_LOAD_NO_BITMAP;
533
534         if ( type & ftc_old_image_flag_unscaled )
535           load_flags |= FT_LOAD_NO_SCALE;
536       }
537
538       /* always render glyphs to bitmaps */
539       load_flags |= FT_LOAD_RENDER;
540
541       if ( type & ftc_old_image_flag_unhinted )
542         load_flags |= FT_LOAD_NO_HINTING;
543
544       if ( type & ftc_old_image_flag_autohinted )
545         load_flags |= FT_LOAD_FORCE_AUTOHINT;
546
547       typ->flags = load_flags;
548     }
549   }
550
551
552   FT_EXPORT( FT_Error )
553   FTC_Image_Cache_New( FTC_Manager      manager,
554                        FTC_ImageCache  *acache );
555
556   FT_EXPORT( FT_Error )
557   FTC_Image_Cache_Lookup( FTC_ImageCache      icache,
558                           FTC_OldImage_Desc*  desc,
559                           FT_UInt             gindex,
560                           FT_Glyph           *aglyph );
561
562
563   FT_EXPORT_DEF( FT_Error )
564   FTC_Image_Cache_New( FTC_Manager      manager,
565                        FTC_ImageCache  *acache )
566   {
567     return FTC_ImageCache_New( manager, (FTC_ImageCache*)acache );
568   }
569
570
571
572   FT_EXPORT_DEF( FT_Error )
573   FTC_Image_Cache_Lookup( FTC_ImageCache      icache,
574                           FTC_OldImage_Desc*  desc,
575                           FT_UInt             gindex,
576                           FT_Glyph           *aglyph )
577   {
578     FTC_ImageTypeRec  type0;
579
580
581     if ( !desc )
582       return FTC_Err_Invalid_Argument;
583
584     ftc_image_type_from_old_desc( &type0, desc );
585
586     return FTC_ImageCache_Lookup( (FTC_ImageCache)icache,
587                                    &type0,
588                                    gindex,
589                                    aglyph,
590                                    NULL );
591   }
592
593 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
594
595
596  /*
597   *
598   * basic small bitmap cache
599   *
600   */
601
602
603   FT_CALLBACK_TABLE_DEF
604   const FTC_SFamilyClassRec  ftc_basic_sbit_family_class =
605   {
606     {
607       sizeof( FTC_BasicFamilyRec ),
608       ftc_basic_family_compare,
609       ftc_basic_family_init,
610       0,                            /* FTC_MruNode_ResetFunc */
611       0                             /* FTC_MruNode_DoneFunc  */
612     },
613     ftc_basic_family_get_count,
614     ftc_basic_family_load_bitmap
615   };
616
617
618   FT_CALLBACK_TABLE_DEF
619   const FTC_GCacheClassRec  ftc_basic_sbit_cache_class =
620   {
621     {
622       ftc_snode_new,
623       ftc_snode_weight,
624       ftc_snode_compare,
625       ftc_basic_gnode_compare_faceid,
626       ftc_snode_free,
627
628       sizeof ( FTC_GCacheRec ),
629       ftc_gcache_init,
630       ftc_gcache_done
631     },
632     (FTC_MruListClass)&ftc_basic_sbit_family_class
633   };
634
635
636   /* documentation is in ftcache.h */
637
638   FT_EXPORT_DEF( FT_Error )
639   FTC_SBitCache_New( FTC_Manager     manager,
640                      FTC_SBitCache  *acache )
641   {
642     return FTC_GCache_New( manager, &ftc_basic_sbit_cache_class,
643                            (FTC_GCache*)acache );
644   }
645
646
647   /* documentation is in ftcache.h */
648
649   FT_EXPORT_DEF( FT_Error )
650   FTC_SBitCache_Lookup( FTC_SBitCache  cache,
651                         FTC_ImageType  type,
652                         FT_UInt        gindex,
653                         FTC_SBit      *ansbit,
654                         FTC_Node      *anode )
655   {
656     FT_Error           error;
657     FTC_BasicQueryRec  query;
658     FTC_Node           node = 0; /* make compiler happy */
659     FT_UInt32          hash;
660
661
662     if ( anode )
663       *anode = NULL;
664
665     /* other argument checks delayed to FTC_Cache_Lookup */
666     if ( !ansbit )
667       return FTC_Err_Invalid_Argument;
668
669     *ansbit = NULL;
670
671 #if defined( FT_CONFIG_OPTION_OLD_INTERNALS ) && ( FT_INT_MAX > 0xFFFFU )
672
673     /*  This one is a major hack used to detect whether we are passed a
674      *  regular FTC_ImageType handle, or a legacy FTC_OldImageDesc one.
675      */
676     if ( (FT_ULong)type->width >= 0x10000L )
677     {
678       FTC_OldImageDesc  desc = (FTC_OldImageDesc)type;
679
680
681       query.attrs.scaler.face_id = desc->font.face_id;
682       query.attrs.scaler.width   = desc->font.pix_width;
683       query.attrs.scaler.height  = desc->font.pix_height;
684       query.attrs.load_flags     = desc->flags;
685     }
686     else
687
688 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
689
690     {
691       if ( (FT_ULong)(type->flags - FT_INT_MIN) > FT_UINT_MAX )
692       {
693         FT_TRACE1(( "FTC_ImageCache_Lookup: higher bits in load_flags" ));
694         FT_TRACE1(( "0x%x are dropped\n", (type->flags & ~((FT_ULong)FT_UINT_MAX)) ));
695       }
696
697       query.attrs.scaler.face_id = type->face_id;
698       query.attrs.scaler.width   = type->width;
699       query.attrs.scaler.height  = type->height;
700       query.attrs.load_flags     = (FT_UInt)type->flags;
701     }
702
703     query.attrs.scaler.pixel = 1;
704     query.attrs.scaler.x_res = 0;  /* make compilers happy */
705     query.attrs.scaler.y_res = 0;
706
707     /* beware, the hash must be the same for all glyph ranges! */
708     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
709            gindex / FTC_SBIT_ITEMS_PER_NODE;
710
711 #if 1  /* inlining is about 50% faster! */
712     FTC_GCACHE_LOOKUP_CMP( cache,
713                            ftc_basic_family_compare,
714                            FTC_SNode_Compare,
715                            hash, gindex,
716                            &query,
717                            node,
718                            error );
719 #else
720     error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
721                                hash,
722                                gindex,
723                                FTC_GQUERY( &query ),
724                                &node );
725 #endif
726     if ( error )
727       goto Exit;
728
729     *ansbit = FTC_SNODE( node )->sbits +
730               ( gindex - FTC_GNODE( node )->gindex );
731
732     if ( anode )
733     {
734       *anode = node;
735       node->ref_count++;
736     }
737
738   Exit:
739     return error;
740   }
741
742
743   /* documentation is in ftcache.h */
744
745   FT_EXPORT_DEF( FT_Error )
746   FTC_SBitCache_LookupScaler( FTC_SBitCache  cache,
747                               FTC_Scaler     scaler,
748                               FT_ULong       load_flags,
749                               FT_UInt        gindex,
750                               FTC_SBit      *ansbit,
751                               FTC_Node      *anode )
752   {
753     FT_Error           error;
754     FTC_BasicQueryRec  query;
755     FTC_Node           node = 0; /* make compiler happy */
756     FT_UInt32          hash;
757
758
759     if ( anode )
760         *anode = NULL;
761
762     /* other argument checks delayed to FTC_Cache_Lookup */
763     if ( !ansbit || !scaler )
764         return FTC_Err_Invalid_Argument;
765
766     *ansbit = NULL;
767
768     /* FT_Load_Glyph(), FT_Load_Char() take FT_UInt flags */
769     if ( load_flags > FT_UINT_MAX )
770     {
771       FT_TRACE1(( "FTC_ImageCache_LookupScaler: higher bits in load_flags" ));
772       FT_TRACE1(( "0x%x are dropped\n", (load_flags & ~((FT_ULong)FT_UINT_MAX)) ));
773     }
774
775     query.attrs.scaler     = scaler[0];
776     query.attrs.load_flags = (FT_UInt)load_flags;
777
778     /* beware, the hash must be the same for all glyph ranges! */
779     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
780              gindex / FTC_SBIT_ITEMS_PER_NODE;
781
782     FTC_GCACHE_LOOKUP_CMP( cache,
783                            ftc_basic_family_compare,
784                            FTC_SNode_Compare,
785                            hash, gindex,
786                            &query,
787                            node,
788                            error );
789     if ( error )
790       goto Exit;
791
792     *ansbit = FTC_SNODE( node )->sbits +
793               ( gindex - FTC_GNODE( node )->gindex );
794
795     if ( anode )
796     {
797       *anode = node;
798       node->ref_count++;
799     }
800
801   Exit:
802     return error;
803   }
804
805
806 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
807
808   FT_EXPORT( FT_Error )
809   FTC_SBit_Cache_New( FTC_Manager     manager,
810                       FTC_SBitCache  *acache );
811
812   FT_EXPORT( FT_Error )
813   FTC_SBit_Cache_Lookup( FTC_SBitCache       cache,
814                          FTC_OldImage_Desc*  desc,
815                          FT_UInt             gindex,
816                          FTC_SBit           *ansbit );
817
818
819   FT_EXPORT_DEF( FT_Error )
820   FTC_SBit_Cache_New( FTC_Manager     manager,
821                       FTC_SBitCache  *acache )
822   {
823     return FTC_SBitCache_New( manager, (FTC_SBitCache*)acache );
824   }
825
826
827   FT_EXPORT_DEF( FT_Error )
828   FTC_SBit_Cache_Lookup( FTC_SBitCache       cache,
829                          FTC_OldImage_Desc*  desc,
830                          FT_UInt             gindex,
831                          FTC_SBit           *ansbit )
832   {
833     FTC_ImageTypeRec  type0;
834
835
836     if ( !desc )
837       return FTC_Err_Invalid_Argument;
838
839     ftc_image_type_from_old_desc( &type0, desc );
840
841     return FTC_SBitCache_Lookup( (FTC_SBitCache)cache,
842                                   &type0,
843                                   gindex,
844                                   ansbit,
845                                   NULL );
846   }
847
848 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
849
850
851 /* END */