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