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