• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  *
3  * ftcbasic.c
4  *
5  *   The FreeType basic cache interface (body).
6  *
7  * Copyright (C) 2003-2022 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 <freetype/internal/ftobjs.h>
20 #include <freetype/internal/ftdebug.h>
21 #include <freetype/ftcache.h>
22 #include "ftcglyph.h"
23 #include "ftcimage.h"
24 #include "ftcsbits.h"
25 
26 #include "ftccback.h"
27 #include "ftcerror.h"
28 
29 #undef  FT_COMPONENT
30 #define FT_COMPONENT  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 )
ftc_basic_family_compare(FTC_MruNode ftcfamily,FT_Pointer ftcquery)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 )
ftc_basic_family_init(FTC_MruNode ftcfamily,FT_Pointer ftcquery,FT_Pointer ftccache)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 )
ftc_basic_family_get_count(FTC_Family ftcfamily,FTC_Manager manager)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 #ifdef FT_DEBUG_LEVEL_TRACE
113     if ( (FT_ULong)face->num_glyphs > FT_UINT_MAX || 0 > face->num_glyphs )
114     {
115       FT_TRACE1(( "ftc_basic_family_get_count:"
116                   " the number of glyphs in this face is %ld,\n",
117                   face->num_glyphs ));
118       FT_TRACE1(( "                           "
119                   " which is too much and thus truncated\n" ));
120     }
121 #endif
122 
123     if ( !error )
124       result = (FT_UInt)face->num_glyphs;
125 
126     return result;
127   }
128 
129 
130   FT_CALLBACK_DEF( FT_Error )
ftc_basic_family_load_bitmap(FTC_Family ftcfamily,FT_UInt gindex,FTC_Manager manager,FT_Face * aface)131   ftc_basic_family_load_bitmap( FTC_Family   ftcfamily,
132                                 FT_UInt      gindex,
133                                 FTC_Manager  manager,
134                                 FT_Face     *aface )
135   {
136     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
137     FT_Error         error;
138     FT_Size          size;
139 
140 
141     error = FTC_Manager_LookupSize( manager, &family->attrs.scaler, &size );
142     if ( !error )
143     {
144       FT_Face  face = size->face;
145 
146 
147       error = FT_Load_Glyph(
148                 face,
149                 gindex,
150                 (FT_Int)family->attrs.load_flags | FT_LOAD_RENDER );
151       if ( !error )
152         *aface = face;
153     }
154 
155     return error;
156   }
157 
158 
159   FT_CALLBACK_DEF( FT_Error )
ftc_basic_family_load_glyph(FTC_Family ftcfamily,FT_UInt gindex,FTC_Cache cache,FT_Glyph * aglyph)160   ftc_basic_family_load_glyph( FTC_Family  ftcfamily,
161                                FT_UInt     gindex,
162                                FTC_Cache   cache,
163                                FT_Glyph   *aglyph )
164   {
165     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
166     FT_Error         error;
167     FTC_Scaler       scaler = &family->attrs.scaler;
168     FT_Face          face;
169     FT_Size          size;
170 
171 
172     /* we will now load the glyph image */
173     error = FTC_Manager_LookupSize( cache->manager,
174                                     scaler,
175                                     &size );
176     if ( !error )
177     {
178       face = size->face;
179 
180       error = FT_Load_Glyph( face,
181                              gindex,
182                              (FT_Int)family->attrs.load_flags );
183       if ( !error )
184       {
185         if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP  ||
186              face->glyph->format == FT_GLYPH_FORMAT_OUTLINE ||
187              face->glyph->format == FT_GLYPH_FORMAT_SVG     )
188         {
189           /* ok, copy it */
190           FT_Glyph  glyph;
191 
192 
193           error = FT_Get_Glyph( face->glyph, &glyph );
194           if ( !error )
195           {
196             *aglyph = glyph;
197             goto Exit;
198           }
199         }
200         else
201           error = FT_THROW( Invalid_Argument );
202       }
203     }
204 
205   Exit:
206     return error;
207   }
208 
209 
210   FT_CALLBACK_DEF( FT_Bool )
ftc_basic_gnode_compare_faceid(FTC_Node ftcgnode,FT_Pointer ftcface_id,FTC_Cache cache,FT_Bool * list_changed)211   ftc_basic_gnode_compare_faceid( FTC_Node    ftcgnode,
212                                   FT_Pointer  ftcface_id,
213                                   FTC_Cache   cache,
214                                   FT_Bool*    list_changed )
215   {
216     FTC_GNode        gnode   = (FTC_GNode)ftcgnode;
217     FTC_FaceID       face_id = (FTC_FaceID)ftcface_id;
218     FTC_BasicFamily  family  = (FTC_BasicFamily)gnode->family;
219     FT_Bool          result;
220 
221 
222     if ( list_changed )
223       *list_changed = FALSE;
224     result = FT_BOOL( family->attrs.scaler.face_id == face_id );
225     if ( result )
226     {
227       /* we must call this function to avoid this node from appearing
228        * in later lookups with the same face_id!
229        */
230       FTC_GNode_UnselectFamily( gnode, cache );
231     }
232     return result;
233   }
234 
235 
236  /*
237   *
238   * basic image cache
239   *
240   */
241 
242   static
243   const FTC_IFamilyClassRec  ftc_basic_image_family_class =
244   {
245     {
246       sizeof ( FTC_BasicFamilyRec ),
247 
248       ftc_basic_family_compare, /* FTC_MruNode_CompareFunc  node_compare */
249       ftc_basic_family_init,    /* FTC_MruNode_InitFunc     node_init    */
250       NULL,                     /* FTC_MruNode_ResetFunc    node_reset   */
251       NULL                      /* FTC_MruNode_DoneFunc     node_done    */
252     },
253 
254     ftc_basic_family_load_glyph /* FTC_IFamily_LoadGlyphFunc  family_load_glyph */
255   };
256 
257 
258   static
259   const FTC_GCacheClassRec  ftc_basic_image_cache_class =
260   {
261     {
262       ftc_inode_new,                  /* FTC_Node_NewFunc      node_new           */
263       ftc_inode_weight,               /* FTC_Node_WeightFunc   node_weight        */
264       ftc_gnode_compare,              /* FTC_Node_CompareFunc  node_compare       */
265       ftc_basic_gnode_compare_faceid, /* FTC_Node_CompareFunc  node_remove_faceid */
266       ftc_inode_free,                 /* FTC_Node_FreeFunc     node_free          */
267 
268       sizeof ( FTC_GCacheRec ),
269       ftc_gcache_init,                /* FTC_Cache_InitFunc    cache_init         */
270       ftc_gcache_done                 /* FTC_Cache_DoneFunc    cache_done         */
271     },
272 
273     (FTC_MruListClass)&ftc_basic_image_family_class
274   };
275 
276 
277   /* documentation is in ftcache.h */
278 
279   FT_EXPORT_DEF( FT_Error )
FTC_ImageCache_New(FTC_Manager manager,FTC_ImageCache * acache)280   FTC_ImageCache_New( FTC_Manager      manager,
281                       FTC_ImageCache  *acache )
282   {
283     return FTC_GCache_New( manager, &ftc_basic_image_cache_class,
284                            (FTC_GCache*)acache );
285   }
286 
287 
288   /* documentation is in ftcache.h */
289 
290   FT_EXPORT_DEF( FT_Error )
FTC_ImageCache_Lookup(FTC_ImageCache cache,FTC_ImageType type,FT_UInt gindex,FT_Glyph * aglyph,FTC_Node * anode)291   FTC_ImageCache_Lookup( FTC_ImageCache  cache,
292                          FTC_ImageType   type,
293                          FT_UInt         gindex,
294                          FT_Glyph       *aglyph,
295                          FTC_Node       *anode )
296   {
297     FTC_BasicQueryRec  query;
298     FTC_Node           node = 0; /* make compiler happy */
299     FT_Error           error;
300     FT_Offset          hash;
301 
302 
303     /* some argument checks are delayed to `FTC_Cache_Lookup' */
304     if ( !aglyph )
305     {
306       error = FT_THROW( Invalid_Argument );
307       goto Exit;
308     }
309 
310     *aglyph = NULL;
311     if ( anode )
312       *anode  = NULL;
313 
314     /*
315      * Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt',
316      * but public `FT_ImageType->flags' is of type `FT_Int32'.
317      *
318      * On 16bit systems, higher bits of type->flags cannot be handled.
319      */
320 #if 0xFFFFFFFFUL > FT_UINT_MAX
321     if ( (type->flags & (FT_ULong)FT_UINT_MAX) )
322       FT_TRACE1(( "FTC_ImageCache_Lookup:"
323                   " higher bits in load_flags 0x%x are dropped\n",
324                   (FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) ));
325 #endif
326 
327     query.attrs.scaler.face_id = type->face_id;
328     query.attrs.scaler.width   = type->width;
329     query.attrs.scaler.height  = type->height;
330     query.attrs.load_flags     = (FT_UInt)type->flags;
331 
332     query.attrs.scaler.pixel = 1;
333     query.attrs.scaler.x_res = 0;  /* make compilers happy */
334     query.attrs.scaler.y_res = 0;
335 
336     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
337 
338 #if 1  /* inlining is about 50% faster! */
339     FTC_GCACHE_LOOKUP_CMP( cache,
340                            ftc_basic_family_compare,
341                            FTC_GNode_Compare,
342                            hash, gindex,
343                            &query,
344                            node,
345                            error );
346 #else
347     error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
348                                hash, gindex,
349                                FTC_GQUERY( &query ),
350                                &node );
351 #endif
352     if ( !error )
353     {
354       *aglyph = FTC_INODE( node )->glyph;
355 
356       if ( anode )
357       {
358         *anode = node;
359         node->ref_count++;
360       }
361     }
362 
363   Exit:
364     return error;
365   }
366 
367 
368   /* documentation is in ftcache.h */
369 
370   FT_EXPORT_DEF( FT_Error )
FTC_ImageCache_LookupScaler(FTC_ImageCache cache,FTC_Scaler scaler,FT_ULong load_flags,FT_UInt gindex,FT_Glyph * aglyph,FTC_Node * anode)371   FTC_ImageCache_LookupScaler( FTC_ImageCache  cache,
372                                FTC_Scaler      scaler,
373                                FT_ULong        load_flags,
374                                FT_UInt         gindex,
375                                FT_Glyph       *aglyph,
376                                FTC_Node       *anode )
377   {
378     FTC_BasicQueryRec  query;
379     FTC_Node           node = 0; /* make compiler happy */
380     FT_Error           error;
381     FT_Offset          hash;
382 
383 
384     /* some argument checks are delayed to `FTC_Cache_Lookup' */
385     if ( !aglyph || !scaler )
386     {
387       error = FT_THROW( Invalid_Argument );
388       goto Exit;
389     }
390 
391     *aglyph = NULL;
392     if ( anode )
393       *anode  = NULL;
394 
395     /*
396      * Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt',
397      * but public `FT_Face->face_flags' is of type `FT_Long'.
398      *
399      * On long > int systems, higher bits of load_flags cannot be handled.
400      */
401 #if FT_ULONG_MAX > FT_UINT_MAX
402     if ( load_flags > FT_UINT_MAX )
403       FT_TRACE1(( "FTC_ImageCache_LookupScaler:"
404                   " higher bits in load_flags 0x%lx are dropped\n",
405                   load_flags & ~((FT_ULong)FT_UINT_MAX) ));
406 #endif
407 
408     query.attrs.scaler     = scaler[0];
409     query.attrs.load_flags = (FT_UInt)load_flags;
410 
411     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
412 
413     FTC_GCACHE_LOOKUP_CMP( cache,
414                            ftc_basic_family_compare,
415                            FTC_GNode_Compare,
416                            hash, gindex,
417                            &query,
418                            node,
419                            error );
420     if ( !error )
421     {
422       *aglyph = FTC_INODE( node )->glyph;
423 
424       if ( anode )
425       {
426         *anode = node;
427         node->ref_count++;
428       }
429     }
430 
431   Exit:
432     return error;
433   }
434 
435 
436   /*
437    *
438    * basic small bitmap cache
439    *
440    */
441 
442   static
443   const FTC_SFamilyClassRec  ftc_basic_sbit_family_class =
444   {
445     {
446       sizeof ( FTC_BasicFamilyRec ),
447       ftc_basic_family_compare,     /* FTC_MruNode_CompareFunc  node_compare */
448       ftc_basic_family_init,        /* FTC_MruNode_InitFunc     node_init    */
449       NULL,                         /* FTC_MruNode_ResetFunc    node_reset   */
450       NULL                          /* FTC_MruNode_DoneFunc     node_done    */
451     },
452 
453     ftc_basic_family_get_count,
454     ftc_basic_family_load_bitmap
455   };
456 
457 
458   static
459   const FTC_GCacheClassRec  ftc_basic_sbit_cache_class =
460   {
461     {
462       ftc_snode_new,                  /* FTC_Node_NewFunc      node_new           */
463       ftc_snode_weight,               /* FTC_Node_WeightFunc   node_weight        */
464       ftc_snode_compare,              /* FTC_Node_CompareFunc  node_compare       */
465       ftc_basic_gnode_compare_faceid, /* FTC_Node_CompareFunc  node_remove_faceid */
466       ftc_snode_free,                 /* FTC_Node_FreeFunc     node_free          */
467 
468       sizeof ( FTC_GCacheRec ),
469       ftc_gcache_init,                /* FTC_Cache_InitFunc    cache_init         */
470       ftc_gcache_done                 /* FTC_Cache_DoneFunc    cache_done         */
471     },
472 
473     (FTC_MruListClass)&ftc_basic_sbit_family_class
474   };
475 
476 
477   /* documentation is in ftcache.h */
478 
479   FT_EXPORT_DEF( FT_Error )
FTC_SBitCache_New(FTC_Manager manager,FTC_SBitCache * acache)480   FTC_SBitCache_New( FTC_Manager     manager,
481                      FTC_SBitCache  *acache )
482   {
483     return FTC_GCache_New( manager, &ftc_basic_sbit_cache_class,
484                            (FTC_GCache*)acache );
485   }
486 
487 
488   /* documentation is in ftcache.h */
489 
490   FT_EXPORT_DEF( FT_Error )
FTC_SBitCache_Lookup(FTC_SBitCache cache,FTC_ImageType type,FT_UInt gindex,FTC_SBit * ansbit,FTC_Node * anode)491   FTC_SBitCache_Lookup( FTC_SBitCache  cache,
492                         FTC_ImageType  type,
493                         FT_UInt        gindex,
494                         FTC_SBit      *ansbit,
495                         FTC_Node      *anode )
496   {
497     FT_Error           error;
498     FTC_BasicQueryRec  query;
499     FTC_Node           node = 0; /* make compiler happy */
500     FT_Offset          hash;
501 
502 
503     if ( anode )
504       *anode = NULL;
505 
506     /* other argument checks delayed to `FTC_Cache_Lookup' */
507     if ( !ansbit )
508       return FT_THROW( Invalid_Argument );
509 
510     *ansbit = NULL;
511 
512     /*
513      * Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt',
514      * but public `FT_ImageType->flags' is of type `FT_Int32'.
515      *
516      * On 16bit systems, higher bits of type->flags cannot be handled.
517      */
518 #if 0xFFFFFFFFUL > FT_UINT_MAX
519     if ( (type->flags & (FT_ULong)FT_UINT_MAX) )
520       FT_TRACE1(( "FTC_ImageCache_Lookup:"
521                   " higher bits in load_flags 0x%x are dropped\n",
522                   (FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) ));
523 #endif
524 
525     query.attrs.scaler.face_id = type->face_id;
526     query.attrs.scaler.width   = type->width;
527     query.attrs.scaler.height  = type->height;
528     query.attrs.load_flags     = (FT_UInt)type->flags;
529 
530     query.attrs.scaler.pixel = 1;
531     query.attrs.scaler.x_res = 0;  /* make compilers happy */
532     query.attrs.scaler.y_res = 0;
533 
534     /* beware, the hash must be the same for all glyph ranges! */
535     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
536            gindex / FTC_SBIT_ITEMS_PER_NODE;
537 
538 #if 1  /* inlining is about 50% faster! */
539     FTC_GCACHE_LOOKUP_CMP( cache,
540                            ftc_basic_family_compare,
541                            FTC_SNode_Compare,
542                            hash, gindex,
543                            &query,
544                            node,
545                            error );
546 #else
547     error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
548                                hash,
549                                gindex,
550                                FTC_GQUERY( &query ),
551                                &node );
552 #endif
553     if ( error )
554       goto Exit;
555 
556     *ansbit = FTC_SNODE( node )->sbits +
557               ( gindex - FTC_GNODE( node )->gindex );
558 
559     if ( anode )
560     {
561       *anode = node;
562       node->ref_count++;
563     }
564 
565   Exit:
566     return error;
567   }
568 
569 
570   /* documentation is in ftcache.h */
571 
572   FT_EXPORT_DEF( FT_Error )
FTC_SBitCache_LookupScaler(FTC_SBitCache cache,FTC_Scaler scaler,FT_ULong load_flags,FT_UInt gindex,FTC_SBit * ansbit,FTC_Node * anode)573   FTC_SBitCache_LookupScaler( FTC_SBitCache  cache,
574                               FTC_Scaler     scaler,
575                               FT_ULong       load_flags,
576                               FT_UInt        gindex,
577                               FTC_SBit      *ansbit,
578                               FTC_Node      *anode )
579   {
580     FT_Error           error;
581     FTC_BasicQueryRec  query;
582     FTC_Node           node = 0; /* make compiler happy */
583     FT_Offset          hash;
584 
585 
586     if ( anode )
587         *anode = NULL;
588 
589     /* other argument checks delayed to `FTC_Cache_Lookup' */
590     if ( !ansbit || !scaler )
591         return FT_THROW( Invalid_Argument );
592 
593     *ansbit = NULL;
594 
595     /*
596      * Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt',
597      * but public `FT_Face->face_flags' is of type `FT_Long'.
598      *
599      * On long > int systems, higher bits of load_flags cannot be handled.
600      */
601 #if FT_ULONG_MAX > FT_UINT_MAX
602     if ( load_flags > FT_UINT_MAX )
603       FT_TRACE1(( "FTC_ImageCache_LookupScaler:"
604                   " higher bits in load_flags 0x%lx are dropped\n",
605                   load_flags & ~((FT_ULong)FT_UINT_MAX) ));
606 #endif
607 
608     query.attrs.scaler     = scaler[0];
609     query.attrs.load_flags = (FT_UInt)load_flags;
610 
611     /* beware, the hash must be the same for all glyph ranges! */
612     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
613              gindex / FTC_SBIT_ITEMS_PER_NODE;
614 
615     FTC_GCACHE_LOOKUP_CMP( cache,
616                            ftc_basic_family_compare,
617                            FTC_SNode_Compare,
618                            hash, gindex,
619                            &query,
620                            node,
621                            error );
622     if ( error )
623       goto Exit;
624 
625     *ansbit = FTC_SNODE( node )->sbits +
626               ( gindex - FTC_GNODE( node )->gindex );
627 
628     if ( anode )
629     {
630       *anode = node;
631       node->ref_count++;
632     }
633 
634   Exit:
635     return error;
636   }
637 
638 
639 /* END */
640