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