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